eventmachine 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/pipe.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: pipe.cpp 401 2007-07-11 12:54:06Z blackhedd $
3
+ $Id: pipe.cpp 494 2007-08-15 06:23:09Z blackhedd $
4
4
 
5
5
  File: pipe.cpp
6
6
  Date: 30May07
@@ -27,12 +27,11 @@ See the file COPYING for complete licensing information.
27
27
  PipeDescriptor::PipeDescriptor
28
28
  ******************************/
29
29
 
30
- PipeDescriptor::PipeDescriptor (FILE *fp, pid_t subpid, EventMachine_t *parent_em):
31
- EventableDescriptor (fileno (fp), parent_em),
30
+ PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
31
+ EventableDescriptor (fd, parent_em),
32
32
  bReadAttemptedAfterClose (false),
33
33
  LastIo (gCurrentLoopTime),
34
34
  InactivityTimeout (0),
35
- //MyStream (fp),
36
35
  OutboundDataSize (0),
37
36
  SubprocessPid (subpid)
38
37
  {
data/ext/rubymain.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: rubymain.cpp 476 2007-07-27 03:32:51Z blackhedd $
3
+ $Id: rubymain.cpp 502 2007-08-24 09:29:53Z blackhedd $
4
4
 
5
5
  File: rubymain.cpp
6
6
  Date: 06Apr06
@@ -138,6 +138,21 @@ static VALUE t_start_tls (VALUE self, VALUE signature)
138
138
  return Qnil;
139
139
  }
140
140
 
141
+ /***************
142
+ t_set_tls_parms
143
+ ***************/
144
+
145
+ static VALUE t_set_tls_parms (VALUE self, VALUE signature, VALUE privkeyfile, VALUE certchainfile)
146
+ {
147
+ /* set_tls_parms takes a series of positional arguments for specifying such things
148
+ * as private keys and certificate chains.
149
+ * It's expected that the parameter list will grow as we add more supported features.
150
+ * ALL of these parameters are optional, and can be specified as empty or NULL strings.
151
+ */
152
+ evma_set_tls_parms (StringValuePtr (signature), StringValuePtr (privkeyfile), StringValuePtr (certchainfile) );
153
+ return Qnil;
154
+ }
155
+
141
156
  /**************
142
157
  t_get_peername
143
158
  **************/
@@ -361,6 +376,19 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
361
376
  }
362
377
 
363
378
 
379
+ /***************
380
+ t_read_keyboard
381
+ ***************/
382
+
383
+ static VALUE t_read_keyboard (VALUE self)
384
+ {
385
+ const char *f = evma_open_keyboard();
386
+ if (!f || !*f)
387
+ rb_raise (rb_eRuntimeError, "no keyboard reader");
388
+ return rb_str_new2 (f);
389
+ }
390
+
391
+
364
392
  /********
365
393
  t__epoll
366
394
  ********/
@@ -452,6 +480,7 @@ extern "C" void Init_rubyeventmachine()
452
480
  rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2);
453
481
  rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1);
454
482
  rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
483
+ rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 3);
455
484
  rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
456
485
  rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3);
457
486
  rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5);
@@ -459,6 +488,7 @@ extern "C" void Init_rubyeventmachine()
459
488
  rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2);
460
489
  rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1);
461
490
  rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2);
491
+ rb_define_module_function (EmModule, "read_keyboard", (VALUE(*)(...))t_read_keyboard, 0);
462
492
  rb_define_module_function (EmModule, "release_machine", (VALUE(*)(...))t_release_machine, 0);
463
493
  rb_define_module_function (EmModule, "stop", (VALUE(*)(...))t_stop, 0);
464
494
  rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0);
data/ext/ssl.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ssl.cpp 318 2007-05-22 22:06:24Z blackhedd $
3
+ $Id: ssl.cpp 498 2007-08-15 14:03:32Z blackhedd $
4
4
 
5
5
  File: ssl.cpp
6
6
  Date: 30Apr06
@@ -120,11 +120,19 @@ static void InitializeDefaultCredentials()
120
120
  SslContext_t::SslContext_t
121
121
  **************************/
122
122
 
123
- SslContext_t::SslContext_t (bool is_server):
123
+ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile):
124
124
  pCtx (NULL),
125
125
  PrivateKey (NULL),
126
126
  Certificate (NULL)
127
127
  {
128
+ /* TODO: the usage of the specified private-key and cert-chain filenames only applies to
129
+ * client-side connections at this point. Server connections currently use the default materials.
130
+ * That needs to be fixed asap.
131
+ * Also, in this implementation, server-side connections use statically defined X-509 defaults.
132
+ * One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY
133
+ * objects when we call our destructor, or whether just calling SSL_CTX_free is enough.
134
+ */
135
+
128
136
  if (!bLibraryInitialized) {
129
137
  bLibraryInitialized = true;
130
138
  SSL_library_init();
@@ -159,9 +167,21 @@ SslContext_t::SslContext_t (bool is_server):
159
167
  SSL_CTX_sess_set_cache_size (pCtx, 128);
160
168
  SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12);
161
169
  }
162
-
170
+ else {
171
+ int e;
172
+ if (privkeyfile.length() > 0) {
173
+ e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
174
+ assert (e > 0);
175
+ }
176
+ if (certchainfile.length() > 0) {
177
+ e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
178
+ assert (e > 0);
179
+ }
180
+ }
163
181
  }
164
182
 
183
+
184
+
165
185
  /***************************
166
186
  SslContext_t::~SslContext_t
167
187
  ***************************/
@@ -182,13 +202,17 @@ SslContext_t::~SslContext_t()
182
202
  SslBox_t::SslBox_t
183
203
  ******************/
184
204
 
185
- SslBox_t::SslBox_t (bool is_server):
205
+ SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile):
186
206
  bIsServer (is_server),
187
207
  pSSL (NULL),
188
208
  pbioRead (NULL),
189
209
  pbioWrite (NULL)
190
210
  {
191
- Context = new SslContext_t (bIsServer);
211
+ /* TODO someday: make it possible to re-use SSL contexts so we don't have to create
212
+ * a new one every time we come here.
213
+ */
214
+
215
+ Context = new SslContext_t (bIsServer, privkeyfile, certchainfile);
192
216
  assert (Context);
193
217
 
194
218
  pbioRead = BIO_new (BIO_s_mem());
data/ext/ssl.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ssl.h 318 2007-05-22 22:06:24Z blackhedd $
3
+ $Id: ssl.h 498 2007-08-15 14:03:32Z blackhedd $
4
4
 
5
5
  File: ssl.h
6
6
  Date: 30Apr06
@@ -33,7 +33,7 @@ class SslContext_t
33
33
  class SslContext_t
34
34
  {
35
35
  public:
36
- SslContext_t (bool is_server);
36
+ SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
37
37
  virtual ~SslContext_t();
38
38
 
39
39
  private:
@@ -57,7 +57,7 @@ class SslBox_t
57
57
  class SslBox_t
58
58
  {
59
59
  public:
60
- SslBox_t (bool is_server);
60
+ SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile);
61
61
  virtual ~SslBox_t();
62
62
 
63
63
  int PutPlaintext (const char*, int);
data/lib/em/deferrable.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: deferrable.rb 464 2007-07-22 12:56:27Z blackhedd $
1
+ # $Id: deferrable.rb 534 2007-09-15 23:06:15Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -28,26 +28,50 @@ require 'forwardable'
28
28
  module EventMachine
29
29
 
30
30
  module Deferrable
31
+
32
+ # Specify a block to be executed if and when the Deferrable object receives
33
+ # a status of :succeeded. See #set_deferred_status for more information.
34
+ #
35
+ # Calling this method on a Deferrable object whose status is not yet known
36
+ # will cause the callback block to be stored on an internal list.
37
+ # If you call this method on a Deferrable whose status is :succeeded, the
38
+ # block will be executed immediately, receiving the parameters given to the
39
+ # prior #set_deferred_status call.
40
+ #
41
+ #--
42
+ # If there is no status, add a callback to an internal list.
43
+ # If status is succeeded, execute the callback immediately.
44
+ # If status is failed, do nothing.
45
+ #
31
46
  def callback &block
32
47
  return unless block
33
48
  if @deferred_status == :succeeded
34
49
  block.call(*@deferred_args)
35
- else
50
+ elsif @deferred_status != :failed
36
51
  @callbacks ||= []
37
52
  @callbacks.unshift block # << block
38
53
  end
39
54
  end
40
55
 
56
+ # Specify a block to be executed if and when the Deferrable object receives
57
+ # a status of :failed. See #set_deferred_status for more information.
58
+ #--
59
+ # If there is no status, add an errback to an internal list.
60
+ # If status is failed, execute the errback immediately.
61
+ # If status is succeeded, do nothing.
62
+ #
41
63
  def errback &block
42
64
  return unless block
43
65
  if @deferred_status == :failed
44
66
  block.call(*@deferred_args)
45
- else
67
+ elsif @deferred_status != :succeeded
46
68
  @errbacks ||= []
47
69
  @errbacks.unshift block # << block
48
70
  end
49
71
  end
50
72
 
73
+ # Sets the "disposition" (status) of the Deferrable object. See also the large set of
74
+ # sugarings for this method.
51
75
  # Note that if you call this method without arguments,
52
76
  # no arguments will be passed to the callback/errback.
53
77
  # If the user has coded these with arguments, then the
@@ -59,6 +83,23 @@ module Deferrable
59
83
  # on the INSIDE of a callback. This is very useful when a previously-registered
60
84
  # callback wants to change the parameters that will be passed to subsequently-registered
61
85
  # ones.
86
+ #
87
+ # You may give either :succeeded or :failed as the status argument.
88
+ #
89
+ # If you pass :succeeded, then all of the blocks passed to the object using the #callback
90
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
91
+ # passed to the object using #errback will be discarded.
92
+ #
93
+ # If you pass :failed, then all of the blocks passed to the object using the #errback
94
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
95
+ # passed to the object using # callback will be discarded.
96
+ #
97
+ # If you pass any arguments to #set_deferred_status in addition to the status argument,
98
+ # they will be passed as arguments to any callbacks or errbacks that are executed.
99
+ # It's your responsibility to ensure that the argument lists specified in your callbacks and
100
+ # errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
101
+ # an ArgumentError.
102
+ #
62
103
  # --
63
104
  # We're shifting callbacks off and discarding them as we execute them.
64
105
  # This is valid because by definition callbacks are executed no more than
@@ -70,25 +111,65 @@ module Deferrable
70
111
  # by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
71
112
  # versions.
72
113
  #
73
- def set_deferred_status arg, *args
74
- @deferred_status = arg
114
+ # Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
115
+ # handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
116
+ # which only allows status to be set once. Prior to making this change, it was possible
117
+ # to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
118
+ # triggering its errbacks! That is clearly undesirable, but it's just as undesirable
119
+ # to raise an exception is status is set more than once on a Deferrable. The latter
120
+ # behavior would invalidate the idiom of resetting arguments by setting status from
121
+ # within a callback or errback, but more seriously it would cause spurious errors
122
+ # if a Deferrable was timed out and then an attempt was made to succeed it. See the
123
+ # comments under the new method #timeout.
124
+ #
125
+ def set_deferred_status status, *args
126
+ cancel_timeout
127
+ @deferred_status = status
75
128
  @deferred_args = args
76
129
  case @deferred_status
77
130
  when :succeeded
78
131
  if @callbacks
79
- while cb = @callbacks.pop #shift
132
+ while cb = @callbacks.pop
80
133
  cb.call(*@deferred_args)
81
134
  end
82
135
  end
136
+ @errbacks.clear if @errbacks
83
137
  when :failed
84
138
  if @errbacks
85
- while eb = @errbacks.pop #shift
139
+ while eb = @errbacks.pop
86
140
  eb.call(*@deferred_args)
87
141
  end
88
142
  end
143
+ @callbacks.clear if @callbacks
89
144
  end
90
145
  end
91
146
 
147
+
148
+ # Setting a timeout on a Deferrable causes it to go into the failed state after
149
+ # the Timeout expires (passing no arguments to the object's errbacks).
150
+ # Setting the status at any time prior to a call to the expiration of the timeout
151
+ # will cause the timer to be cancelled.
152
+ #--
153
+ #
154
+ #
155
+ def timeout seconds
156
+ cancel_timeout
157
+ me = self
158
+ @deferred_timeout = EventMachine::Timer.new(seconds) {me.fail}
159
+ end
160
+
161
+
162
+ # Cancels an outstanding timeout if any. Undoes the action of #timeout.
163
+ #
164
+ #
165
+ def cancel_timeout
166
+ if @deferred_timeout
167
+ @deferred_timeout.cancel
168
+ @deferred_timeout = nil
169
+ end
170
+ end
171
+
172
+
92
173
  # Equivalent to set_deferred_status(:succeeded, ...)
93
174
  #
94
175
  def set_deferred_success *args
@@ -104,13 +185,13 @@ module Deferrable
104
185
  # And still more sugar
105
186
  #
106
187
  def succeed *args
107
- set_deferred_success *args
188
+ set_deferred_success(*args)
108
189
  end
109
190
 
110
191
  # Can't get enough sugar
111
192
  #
112
193
  def fail *args
113
- set_deferred_failure *args
194
+ set_deferred_failure(*args)
114
195
  end
115
196
  end
116
197
 
@@ -0,0 +1,88 @@
1
+ # $Id: spawnable.rb 530 2007-09-13 01:11:38Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 25 Aug 2007
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+
27
+ # Support for Erlang-style processes.
28
+ #
29
+
30
+
31
+ module EventMachine
32
+ class SpawnedProcess
33
+ #attr_accessor :receiver
34
+ def notify *x
35
+ me = self
36
+ EM.next_tick {
37
+ # A notification executes in the context of this
38
+ # SpawnedProcess object. That makes self and notify
39
+ # work as one would expect.
40
+ #
41
+ y = me.call(*x)
42
+ if y and y.respond_to?(:pull_out_yield_block)
43
+ a,b = y.pull_out_yield_block
44
+ set_receiver a
45
+ self.notify if b
46
+ end
47
+ }
48
+ end
49
+ alias_method :resume, :notify
50
+ alias_method :run, :notify # for formulations like (EM.spawn {xxx}).run
51
+
52
+ # I know I'm missing something stupid, but the inside of class << s
53
+ # can't see locally-bound values. It can see globals, though.
54
+ def set_receiver blk
55
+ $em______tmpglobal = blk
56
+ class << self
57
+ define_method :call, $em______tmpglobal.dup
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ class YieldBlockFromSpawnedProcess
64
+ def initialize block, notify
65
+ @block = [block,notify]
66
+ end
67
+ def pull_out_yield_block
68
+ @block
69
+ end
70
+ end
71
+
72
+ def EventMachine.spawn &block
73
+ s = SpawnedProcess.new
74
+ s.set_receiver block
75
+ s
76
+ end
77
+
78
+ def EventMachine.yield &block
79
+ return YieldBlockFromSpawnedProcess.new( block, false )
80
+ end
81
+
82
+ def EventMachine.yield_and_notify &block
83
+ return YieldBlockFromSpawnedProcess.new( block, true )
84
+ end
85
+ end
86
+
87
+
88
+
data/lib/eventmachine.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: eventmachine.rb 489 2007-07-30 05:10:15Z blackhedd $
1
+ # $Id: eventmachine.rb 521 2007-09-04 18:22:07Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -66,6 +66,7 @@ require 'em/future'
66
66
  require 'em/eventable'
67
67
  require 'em/messages'
68
68
  require 'em/streamer'
69
+ require 'em/spawnable'
69
70
 
70
71
  require 'shellwords'
71
72
 
@@ -216,15 +217,31 @@ module EventMachine
216
217
  @acceptors = {}
217
218
  @timers = {}
218
219
  begin
220
+ @reactor_running = true
219
221
  initialize_event_machine
220
222
  block and add_timer 0, block
221
223
  run_machine
222
224
  ensure
223
225
  release_machine
226
+ @reactor_running = false
224
227
  end
225
228
  end
226
229
 
227
230
 
231
+ # Sugars a common use case. Will pass the given block to #run, but will terminate
232
+ # the reactor loop and exit the function as soon as the code in the block completes.
233
+ # (Normally, #run keeps running indefinitely, even after the block supplied to it
234
+ # finishes running, until user code calls #stop.)
235
+ #
236
+ def EventMachine::run_block &block
237
+ pr = proc {
238
+ block.call
239
+ EventMachine::stop
240
+ }
241
+ run(&pr)
242
+ end
243
+
244
+
228
245
  # +deprecated+
229
246
  #--
230
247
  # EventMachine#run_without_threads is semantically identical
@@ -766,17 +783,27 @@ module EventMachine
766
783
  # It can be fired either by code running on a separate thread (EM#defer) or on
767
784
  # the main thread (EM#next_tick).
768
785
  # It will often happen that a next_tick handler will reschedule itself. We
769
- # consume a duplicate of the tick queue so that tick events scheduled by tick events
786
+ # consume a copy of the tick queue so that tick events scheduled by tick events
770
787
  # have to wait for the next pass through the reactor core.
771
788
  #
772
789
  def self::run_deferred_callbacks # :nodoc:
773
- if @resultqueue
774
- until @resultqueue.empty?
775
- result,cback = @resultqueue.pop
776
- cback.call result if cback
777
- end
790
+ until (@resultqueue ||= []).empty?
791
+ result,cback = @resultqueue.pop
792
+ cback.call result if cback
778
793
  end
779
794
 
795
+ @next_tick_queue ||= []
796
+ if (l = @next_tick_queue.length) > 0
797
+ l.times {|i| @next_tick_queue[i].call}
798
+ @next_tick_queue.slice!( 0...l )
799
+ end
800
+
801
+ =begin
802
+ (@next_tick_queue ||= []).length.times {
803
+ cback=@next_tick_queue.pop and cback.call
804
+ }
805
+ =end
806
+ =begin
780
807
  if (@next_tick_queue ||= []) and @next_tick_queue.length > 0
781
808
  ary = @next_tick_queue.dup
782
809
  @next_tick_queue.clear
@@ -784,6 +811,7 @@ module EventMachine
784
811
  cback=ary.pop and cback.call
785
812
  end
786
813
  end
814
+ =end
787
815
  end
788
816
 
789
817
 
@@ -810,7 +838,6 @@ module EventMachine
810
838
  # after the operation completes.
811
839
  #
812
840
  # <i>Caveats:</i>
813
- # This is a <b>provisional</b> implementation and is subject to change.
814
841
  # Note carefully that the code in your deferred operation will be executed on a separate
815
842
  # thread from the main EventMachine processing and all other Ruby threads that may exist in
816
843
  # your program. Also, multiple deferred operations may be running at once! Therefore, you
@@ -872,7 +899,7 @@ module EventMachine
872
899
  #
873
900
  def self::next_tick pr=nil, &block
874
901
  raise "no argument or block given" unless ((pr && pr.respond_to?(:call)) or block)
875
- (@next_tick_queue ||= []) << (pr || block)
902
+ (@next_tick_queue ||= []) << ( pr || block )
876
903
  EventMachine.signal_loopbreak
877
904
  =begin
878
905
  (@next_tick_procs ||= []) << (pr || block)
@@ -944,6 +971,39 @@ module EventMachine
944
971
  end
945
972
 
946
973
 
974
+ # Tells you whether the EventMachine reactor loop is currently running. Returns true or
975
+ # false. Useful when writing libraries that want to run event-driven code, but may
976
+ # be running in programs that are already event-driven. In such cases, if EventMachine#reactor_running?
977
+ # returns false, your code can invoke EventMachine#run and run your application code inside
978
+ # the block passed to that method. If EventMachine#reactor_running? returns true, just
979
+ # execute your event-aware code.
980
+ #
981
+ # This method is necessary because calling EventMachine#run inside of another call to
982
+ # EventMachine#run generates a fatal error.
983
+ #
984
+ def self::reactor_running?
985
+ (@reactor_running || false)
986
+ end
987
+
988
+
989
+ # (Experimental)
990
+ #
991
+ #
992
+ def EventMachine::open_keyboard handler=nil
993
+ klass = if (handler and handler.is_a?(Class))
994
+ handler
995
+ else
996
+ Class.new( Connection ) {handler and include handler}
997
+ end
998
+
999
+ s = read_keyboard
1000
+ c = klass.new s
1001
+ @conns[s] = c
1002
+ block_given? and yield c
1003
+ c
1004
+ end
1005
+
1006
+
947
1007
 
948
1008
  private
949
1009
  def EventMachine::event_callback conn_binding, opcode, data
@@ -1163,9 +1223,35 @@ class Connection
1163
1223
  # Call #start_tls at any point to initiate TLS encryption on connected streams.
1164
1224
  # The method is smart enough to know whether it should perform a server-side
1165
1225
  # or a client-side handshake. An appropriate place to call #start_tls is in
1166
- # your redefined #post_init method.
1226
+ # your redefined #post_init method, or in the #connection_completed handler for
1227
+ # an outbound connection.
1228
+ #
1229
+ # #start_tls takes an optional parameter hash that allows you to specify certificate
1230
+ # and other options to be used with this Connection object. Here are the currently-supported
1231
+ # options:
1232
+ # :cert_chain_file : takes a String, which is interpreted as the name of a readable file in the
1233
+ # local filesystem. The file is expected to contain a chain of X509 certificates in
1234
+ # PEM format, with the most-resolved certificate at the top of the file, successive
1235
+ # intermediate certs in the middle, and the root (or CA) cert at the bottom.
1236
+ #
1237
+ # :private_key_file : tales a String, which is interpreted as the name of a readable file in the
1238
+ # local filesystem. The file must contain a private key in PEM format.
1239
+ #
1240
+ #--
1241
+ # TODO: support passing an encryption parameter, which can be string or Proc, to get a passphrase
1242
+ # for encrypted private keys.
1243
+ # TODO: support passing key material via raw strings or Procs that return strings instead of
1244
+ # just filenames.
1245
+ # What will get nasty is whether we have to define a location for storing this stuff as files.
1246
+ # In general, the OpenSSL interfaces for dealing with certs and keys in files are much better
1247
+ # behaved than the ones for raw chunks of memory.
1167
1248
  #
1168
- def start_tls
1249
+ def start_tls args={}
1250
+ EventMachine::set_tls_parms(
1251
+ @signature,
1252
+ args[:private_key_file] || "",
1253
+ args[:cert_chain_file] || ""
1254
+ )
1169
1255
  EventMachine::start_tls @signature
1170
1256
  end
1171
1257
 
@@ -1332,4 +1418,6 @@ require 'protocols/line_and_text'
1332
1418
  require 'protocols/header_and_content'
1333
1419
  require 'protocols/linetext2'
1334
1420
  require 'protocols/stomp'
1421
+ require 'protocols/smtpclient'
1422
+ require 'protocols/smtpserver'
1335
1423