eventmachine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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