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
@@ -0,0 +1,13 @@
1
+ pkg
2
+ rdoc
3
+ Makefile
4
+
5
+ *.bundle
6
+ *.dll
7
+ *.so
8
+ *.jar
9
+ *.class
10
+ *.o
11
+ *.log
12
+ *.def
13
+ *.pdb
data/Rakefile CHANGED
@@ -31,7 +31,7 @@ require 'rubygems' unless defined?(Gem)
31
31
  require 'rake' unless defined?(Rake)
32
32
  require 'rake/gempackagetask'
33
33
 
34
- Package = true # Build zips and tarballs?
34
+ Package = false # Build zips and tarballs?
35
35
  Dir.glob('tasks/*.rake').each { |r| Rake.application.add_import r }
36
36
 
37
37
  # e.g. rake EVENTMACHINE_LIBRARY=java for forcing java build tasks as defaults!
@@ -90,7 +90,7 @@ Spec = Gem::Specification.new do |s|
90
90
  s.rdoc_options = %w(--title EventMachine --main docs/README --line-numbers)
91
91
  s.extra_rdoc_files = Dir['docs/*']
92
92
 
93
- s.files = %w(Rakefile) + Dir["{bin,tests,lib,ext,java,tasks}/**/*"]
93
+ s.files = `git ls-files`.split("\n")
94
94
 
95
95
  s.require_path = 'lib'
96
96
 
@@ -98,7 +98,11 @@ Spec = Gem::Specification.new do |s|
98
98
  # is broken. What we could do is CI submission, though, and always terminate
99
99
  # with a positive code...
100
100
  # s.test_file = "tests/testem.rb"
101
- s.extensions = "Rakefile"
101
+
102
+ # XXX Using rake to compile extensions breaks when you have multiple ruby installations
103
+ # and your path isn't set. We can switch back to this once the Gem.exec patch is merged.
104
+ # s.extensions = "Rakefile"
105
+ s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
102
106
 
103
107
  s.author = "Francis Cianfrocca"
104
108
  s.email = "garbagecat10@gmail.com"
@@ -124,6 +128,65 @@ using TCP/IP, especially if custom protocols are required.
124
128
  s.version = EventMachine::VERSION
125
129
  end
126
130
 
131
+ if RUBY_PLATFORM =~ /mswin/
132
+ Spec.platform = 'x86-mswin32-60'
133
+ Spec.files += %w[ lib/rubyeventmachine.so lib/fastfilereaderext.so ]
134
+ Spec.extensions = nil
135
+ end
136
+
137
+ # this is a hack right now, it requires installing msysgit in the global path so it can use tar/curl/etc.
138
+ namespace :win32 do
139
+ task :check_git do
140
+ unless `git` =~ /rebase/
141
+ raise 'git not found, install msys git into the GLOBAL PATH: http://msysgit.googlecode.com/files/Git-1.6.2-preview20090308.exe'
142
+ end
143
+ end
144
+
145
+ task :check_vc6 do
146
+ begin
147
+ raise unless `nmake 2>&1` =~ /Microsoft/
148
+ rescue
149
+ raise 'VC6 not found, please run c:\vc\setvc.bat vc6'
150
+ end
151
+ end
152
+
153
+ task :check_perl do
154
+ unless `perl --version` =~ /ActiveState/
155
+ raise 'ActiveState perl required to build OpenSSL: http://downloads.activestate.com/ActivePerl/Windows/5.10/ActivePerl-5.10.0.1004-MSWin32-x86-287188.msi'
156
+ end
157
+ end
158
+
159
+ task :build_openssl => [:check_git, :check_perl, :check_vc6] do
160
+ mkdir_p 'build'
161
+ chdir 'build' do
162
+ unless File.exists?('openssl-0.9.8j')
163
+ sh 'curl http://www.openssl.org/source/openssl-0.9.8j.tar.gz > openssl.tar.gz'
164
+ sh 'tar zxvf openssl.tar.gz' rescue nil # fails because of symlinks
165
+ end
166
+
167
+ mkdir_p 'local'
168
+ chdir 'openssl-0.9.8j' do
169
+ sh "perl Configure VC-WIN32 --prefix=\"../local/\""
170
+ sh 'ms\do_ms.bat'
171
+ sh 'nmake -f ms\nt.mak install'
172
+ end
173
+
174
+ chdir '../ext' do
175
+ sh 'git clean -fd .'
176
+ end
177
+
178
+ mv 'local/include/openssl', '../ext/'
179
+ mv 'local/lib/ssleay32.lib', '../ext/'
180
+ mv 'local/lib/libeay32.lib', '../ext/'
181
+ end
182
+ end
183
+
184
+ task :gem => :build_openssl do
185
+ Rake::Task['build'].invoke
186
+ Rake::Task['gem'].invoke
187
+ end
188
+ end
189
+
127
190
  namespace :ext do
128
191
  ext_sources = FileList['ext/*.{h,cpp,rb,c}']
129
192
  ffr_sources = FileList['ext/fastfilereader/*.{h,cpp,rb}']
@@ -1,12 +1,6 @@
1
- # $Id$
2
- #
3
- #
4
-
5
- #-------------------------------------------------------------
6
- 01Oct06: Replaced EventMachine#open_datagram_server with a version that can take
7
- a Class or a Module, instead of just a Module. Thanks to Tobias Gustafsson for
8
- pointing out the missing case.
9
-
1
+ 01Oct06: Replaced EventMachine#open_datagram_server with a version that can
2
+ take a Class or a Module, instead of just a Module. Thanks to Tobias
3
+ Gustafsson for pointing out the missing case.
10
4
  04Oct06: Supported subsecond timer resolutions, per request by Jason Roelofs.
11
5
  05Oct06: Added EventMachine#set_quantum, which sets the timer resolution.
12
6
  15Nov06: Added Connection#set_comm_inactivity_timeout.
@@ -180,4 +174,38 @@ danielaquino, macournoyer.
180
174
  - Fixes in EM.defer under start/stop conditions. Reduced scope of threads.
181
175
  23Sep08: Added patch from tmm1 to avoid popen errors on exit.
182
176
  30Sep08: Added File.exists? checks in the args for start_tls, as suggested by
183
- Brian Lopez (brianmario).
177
+ Brian Lopez (brianmario).
178
+ 10Nov08: ruby 1.9 compatibility enhancements
179
+ 28Nov08: Allow for older ruby builds where RARRAY_LEN is not defined
180
+ 03Dec08: allow passing arguments to popen handlers
181
+ 13Jan09: SSL support for httpclient2 (David Smalley)
182
+ 22Jan09: Fixed errors on OSX with the kqueue reactor, fixed errors in the pure
183
+ ruby reactor. Added EM.current_time. Added EM.epoll? and EM.kqueue?
184
+ 27Jan09: Reactor errors are now raised as ruby RuntimeErrors.
185
+ 28Jan09: Documentation patch from alloy
186
+ 29Jan09: (Late sign-off) Use a longer timeout for connect_server (Ilya
187
+ Grigorik)
188
+ 07Feb09: Fix signal handling issues with threads+epoll
189
+ 07Feb09: Use rb_thread_schedule in the epoll reactor
190
+ 07Feb09: Use TRAP_BEG/END and rb_thread_schedule in kqueue reactor
191
+ 08Feb09: Added fastfilereader from swiftiply
192
+ 08Feb09: 1.9 fix for rb_trap_immediate
193
+ 08Feb09: Enable rb_thread_blocking_region for 1.9.0 and 1.9.1
194
+ 10Feb09: Support win32 builds for fastfilereader
195
+ 10Feb09: Added a new event to indicate completion of SSL handshake on TCP
196
+ connections
197
+ 10Feb09: Working get_peer_cert method. Returns the certificate as a Ruby
198
+ String in PEM format. (Jake Douglas)
199
+ 10Feb09: Added EM.get_max_timers
200
+ 11Feb09: Fix compile options for sun compiler (Alasdairrr)
201
+ 11Feb09: get_status returns a Process::Status object
202
+ 12Feb09: Add EM::Protocols::Memcache with simple get/set functionality
203
+ 19Feb09: Add catch-all EM.error_handler
204
+ 20Feb09: Support miniunit (1.9)
205
+ 20Feb09: Return success on content-length = 0 instead of start waiting forever
206
+ (Ugo Riboni)
207
+ 25Feb09: Allow next_tick to be used to pre-schedule reactor operations before
208
+ EM.run
209
+ 26Feb09: Added EM.get_connection_count
210
+ 01Mar09: Switch back to extconf for compiling gem extensions
211
+ 01Mar09: fixed a small bug with basic auth (mmmurf)
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{eventmachine}
5
+ s.version = "0.12.6"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Francis Cianfrocca"]
9
+ s.date = %q{2009-03-07}
10
+ s.description = %q{EventMachine implements a fast, single-threaded engine for arbitrary network communications. It's extremely easy to use in Ruby. EventMachine wraps all interactions with IP sockets, allowing programs to concentrate on the implementation of network protocols. It can be used to create both network servers and clients. To create a server or client, a Ruby program only needs to specify the IP address and port, and provide a Module that implements the communications protocol. Implementations of several standard network protocols are provided with the package, primarily to serve as examples. The real goal of EventMachine is to enable programs to easily interface with other programs using TCP/IP, especially if custom protocols are required.}
11
+ s.email = %q{garbagecat10@gmail.com}
12
+ s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
13
+ s.extra_rdoc_files = ["docs/ChangeLog", "docs/COPYING", "docs/DEFERRABLES", "docs/EPOLL", "docs/GNU", "docs/INSTALL", "docs/KEYBOARD", "docs/LEGAL", "docs/LIGHTWEIGHT_CONCURRENCY", "docs/PURE_RUBY", "docs/README", "docs/RELEASE_NOTES", "docs/SMTP", "docs/SPAWNED_PROCESSES", "docs/TODO"]
14
+ s.files = [".gitignore", "Rakefile", "docs/COPYING", "docs/ChangeLog", "docs/DEFERRABLES", "docs/EPOLL", "docs/GNU", "docs/INSTALL", "docs/KEYBOARD", "docs/LEGAL", "docs/LIGHTWEIGHT_CONCURRENCY", "docs/PURE_RUBY", "docs/README", "docs/RELEASE_NOTES", "docs/SMTP", "docs/SPAWNED_PROCESSES", "docs/TODO", "eventmachine.gemspec", "ext/binder.cpp", "ext/binder.h", "ext/cmain.cpp", "ext/cplusplus.cpp", "ext/ed.cpp", "ext/ed.h", "ext/em.cpp", "ext/em.h", "ext/emwin.cpp", "ext/emwin.h", "ext/epoll.cpp", "ext/epoll.h", "ext/eventmachine.h", "ext/eventmachine_cpp.h", "ext/extconf.rb", "ext/fastfilereader/extconf.rb", "ext/fastfilereader/mapper.cpp", "ext/fastfilereader/mapper.h", "ext/fastfilereader/rubymain.cpp", "ext/files.cpp", "ext/files.h", "ext/kb.cpp", "ext/page.cpp", "ext/page.h", "ext/pipe.cpp", "ext/project.h", "ext/rubymain.cpp", "ext/sigs.cpp", "ext/sigs.h", "ext/ssl.cpp", "ext/ssl.h", "java/.classpath", "java/.project", "java/src/com/rubyeventmachine/Application.java", "java/src/com/rubyeventmachine/Connection.java", "java/src/com/rubyeventmachine/ConnectionFactory.java", "java/src/com/rubyeventmachine/DefaultConnectionFactory.java", "java/src/com/rubyeventmachine/EmReactor.java", "java/src/com/rubyeventmachine/EmReactorException.java", "java/src/com/rubyeventmachine/EventableChannel.java", "java/src/com/rubyeventmachine/EventableDatagramChannel.java", "java/src/com/rubyeventmachine/EventableSocketChannel.java", "java/src/com/rubyeventmachine/PeriodicTimer.java", "java/src/com/rubyeventmachine/Timer.java", "java/src/com/rubyeventmachine/tests/ApplicationTest.java", "java/src/com/rubyeventmachine/tests/ConnectTest.java", "java/src/com/rubyeventmachine/tests/EMTest.java", "java/src/com/rubyeventmachine/tests/TestDatagrams.java", "java/src/com/rubyeventmachine/tests/TestServers.java", "java/src/com/rubyeventmachine/tests/TestTimers.java", "lib/em/deferrable.rb", "lib/em/eventable.rb", "lib/em/future.rb", "lib/em/messages.rb", "lib/em/processes.rb", "lib/em/spawnable.rb", "lib/em/streamer.rb", "lib/eventmachine.rb", "lib/eventmachine_version.rb", "lib/evma.rb", "lib/evma/callback.rb", "lib/evma/container.rb", "lib/evma/factory.rb", "lib/evma/protocol.rb", "lib/evma/reactor.rb", "lib/jeventmachine.rb", "lib/pr_eventmachine.rb", "lib/protocols/buftok.rb", "lib/protocols/header_and_content.rb", "lib/protocols/httpcli2.rb", "lib/protocols/httpclient.rb", "lib/protocols/line_and_text.rb", "lib/protocols/linetext2.rb", "lib/protocols/memcache.rb", "lib/protocols/postgres.rb", "lib/protocols/saslauth.rb", "lib/protocols/smtpclient.rb", "lib/protocols/smtpserver.rb", "lib/protocols/stomp.rb", "lib/protocols/tcptest.rb", "setup.rb", "tasks/cpp.rake", "tasks/project.rake", "tasks/tests.rake", "tests/test_attach.rb", "tests/test_basic.rb", "tests/test_connection_count.rb", "tests/test_defer.rb", "tests/test_epoll.rb", "tests/test_error_handler.rb", "tests/test_errors.rb", "tests/test_eventables.rb", "tests/test_exc.rb", "tests/test_futures.rb", "tests/test_handler_check.rb", "tests/test_hc.rb", "tests/test_httpclient.rb", "tests/test_httpclient2.rb", "tests/test_kb.rb", "tests/test_ltp.rb", "tests/test_ltp2.rb", "tests/test_next_tick.rb", "tests/test_processes.rb", "tests/test_pure.rb", "tests/test_running.rb", "tests/test_sasl.rb", "tests/test_send_file.rb", "tests/test_servers.rb", "tests/test_smtpclient.rb", "tests/test_smtpserver.rb", "tests/test_spawn.rb", "tests/test_ssl_args.rb", "tests/test_ssl_methods.rb", "tests/test_timers.rb", "tests/test_ud.rb", "tests/testem.rb", "web/whatis"]
15
+ s.has_rdoc = true
16
+ s.homepage = %q{http://rubyeventmachine.com}
17
+ s.rdoc_options = ["--title", "EventMachine", "--main", "docs/README", "--line-numbers"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{eventmachine}
20
+ s.rubygems_version = %q{1.3.1}
21
+ s.summary = %q{Ruby/EventMachine library}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -272,6 +272,20 @@ extern "C" void evma_set_tls_parms (const char *binding, const char *privatekey_
272
272
  ed->SetTlsParms (privatekey_filename, certchain_filename);
273
273
  }
274
274
 
275
+ /**************
276
+ evma_get_peer_cert
277
+ **************/
278
+
279
+ #ifdef WITH_SSL
280
+ extern "C" X509 *evma_get_peer_cert (const char *binding)
281
+ {
282
+ ensure_eventmachine("evma_get_peer_cert");
283
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
284
+ if (ed)
285
+ return ed->GetPeerCert();
286
+ return NULL;
287
+ }
288
+ #endif
275
289
 
276
290
  /*****************
277
291
  evma_get_peername
@@ -310,12 +324,20 @@ evma_get_subprocess_pid
310
324
  extern "C" int evma_get_subprocess_pid (const char *binding, pid_t *pid)
311
325
  {
312
326
  ensure_eventmachine("evma_get_subprocess_pid");
313
- EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
314
- if (ed) {
315
- return ed->GetSubprocessPid (pid) ? 1 : 0;
327
+ #ifdef OS_UNIX
328
+ PipeDescriptor *pd = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
329
+ if (pd) {
330
+ return pd->GetSubprocessPid (pid) ? 1 : 0;
331
+ }
332
+ else if (pid && EventMachine->SubprocessPid) {
333
+ *pid = EventMachine->SubprocessPid;
334
+ return 1;
316
335
  }
317
336
  else
318
337
  return 0;
338
+ #else
339
+ return 0;
340
+ #endif
319
341
  }
320
342
 
321
343
  /**************************
@@ -333,6 +355,15 @@ extern "C" int evma_get_subprocess_status (const char *binding, int *status)
333
355
  return 0;
334
356
  }
335
357
 
358
+ /*************************
359
+ evma_get_connection_count
360
+ *************************/
361
+
362
+ extern "C" int evma_get_connection_count()
363
+ {
364
+ ensure_eventmachine("evma_get_connection_count");
365
+ return EventMachine->GetConnectionCount();
366
+ }
336
367
 
337
368
  /*********************
338
369
  evma_signal_loopbreak
@@ -398,6 +429,17 @@ extern "C" void evma_set_timer_quantum (int interval)
398
429
  EventMachine->SetTimerQuantum (interval);
399
430
  }
400
431
 
432
+
433
+ /************************
434
+ evma_get_max_timer_count
435
+ ************************/
436
+
437
+ extern "C" int evma_get_max_timer_count()
438
+ {
439
+ return EventMachine_t::GetMaxTimerCount();
440
+ }
441
+
442
+
401
443
  /************************
402
444
  evma_set_max_timer_count
403
445
  ************************/
@@ -49,7 +49,11 @@ void EM::AddTimer (int milliseconds, void (*func)())
49
49
  {
50
50
  if (func) {
51
51
  const char *sig = evma_install_oneshot_timer (milliseconds);
52
+ #ifdef OS_SOLARIS8
53
+ Timers.insert (map<string, void(*)()>::value_type (sig, func));
54
+ #else
52
55
  Timers.insert (make_pair (sig, func));
56
+ #endif
53
57
  }
54
58
  }
55
59
 
@@ -72,7 +76,11 @@ void EM::Acceptor::Accept (const char *signature)
72
76
  {
73
77
  Connection *c = MakeConnection();
74
78
  c->Signature = signature;
79
+ #ifdef OS_SOLARIS8
80
+ Eventables.insert (std::map<std::string,EM::Eventable*>::value_type (c->Signature, c));
81
+ #else
75
82
  Eventables.insert (make_pair (c->Signature, c));
83
+ #endif
76
84
  c->PostInit();
77
85
  }
78
86
 
@@ -114,7 +122,11 @@ EM::Connection::Connect
114
122
  void EM::Connection::Connect (const char *host, int port)
115
123
  {
116
124
  Signature = evma_connect_to_server (host, port);
125
+ #ifdef OS_SOLARIS8
126
+ Eventables.insert( std::map<std::string,EM::Eventable*>::value_type (Signature, this));
127
+ #else
117
128
  Eventables.insert( make_pair (Signature, this));
129
+ #endif
118
130
  }
119
131
 
120
132
  /*******************
@@ -124,7 +136,11 @@ EM::Acceptor::Start
124
136
  void EM::Acceptor::Start (const char *host, int port)
125
137
  {
126
138
  Signature = evma_create_tcp_server (host, port);
139
+ #ifdef OS_SOLARIS8
140
+ Eventables.insert( std::map<std::string,EM::Eventable*>::value_type (Signature, this));
141
+ #else
127
142
  Eventables.insert( make_pair (Signature, this));
143
+ #endif
128
144
  }
129
145
 
130
146
 
@@ -167,6 +183,11 @@ void EM::Callback (const char *sig, int ev, const char *data, int length)
167
183
  EM::Eventables.erase (sig);
168
184
  delete e;
169
185
  break;
186
+
187
+ case EM_SSL_HANDSHAKE_COMPLETED:
188
+ e = EM::Eventables [sig];
189
+ e->SslHandshakeCompleted();
190
+ break;
170
191
  }
171
192
  }
172
193
 
data/ext/ed.cpp CHANGED
@@ -51,6 +51,7 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
51
51
  LastRead (0),
52
52
  LastWritten (0),
53
53
  bCallbackUnbind (true),
54
+ UnbindReasonCode (0),
54
55
  MyEventMachine (em)
55
56
  {
56
57
  /* There are three ways to close a socket, all of which should
@@ -93,7 +94,7 @@ EventableDescriptor::~EventableDescriptor
93
94
  EventableDescriptor::~EventableDescriptor()
94
95
  {
95
96
  if (EventCallback && bCallbackUnbind)
96
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, 0);
97
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
97
98
  Close();
98
99
  }
99
100
 
@@ -181,6 +182,7 @@ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
181
182
  OutboundDataSize (0),
182
183
  #ifdef WITH_SSL
183
184
  SslBox (NULL),
185
+ bHandshakeSignaled (false),
184
186
  #endif
185
187
  bIsServer (false),
186
188
  LastIo (gCurrentLoopTime),
@@ -495,10 +497,12 @@ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
495
497
  int s;
496
498
  char B [2048];
497
499
  while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
500
+ _CheckHandshakeStatus();
498
501
  B [s] = 0;
499
502
  if (EventCallback)
500
503
  (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, B, s);
501
504
  }
505
+ _CheckHandshakeStatus();
502
506
  // INCOMPLETE, s may indicate an SSL error that would force the connection down.
503
507
  _DispatchCiphertext();
504
508
  }
@@ -516,6 +520,21 @@ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
516
520
 
517
521
 
518
522
 
523
+ /*******************************************
524
+ ConnectionDescriptor::_CheckHandshakeStatus
525
+ *******************************************/
526
+
527
+ void ConnectionDescriptor::_CheckHandshakeStatus()
528
+ {
529
+ #ifdef WITH_SSL
530
+ if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
531
+ bHandshakeSignaled = true;
532
+ if (EventCallback)
533
+ (*EventCallback)(GetBinding().c_str(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
534
+ }
535
+ #endif
536
+ }
537
+
519
538
 
520
539
 
521
540
  /***************************
@@ -737,10 +756,24 @@ void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char
737
756
  }
738
757
 
739
758
 
759
+ /*********************************
760
+ ConnectionDescriptor::GetPeerCert
761
+ *********************************/
762
+
763
+ #ifdef WITH_SSL
764
+ X509 *ConnectionDescriptor::GetPeerCert()
765
+ {
766
+ if (!SslBox)
767
+ throw std::runtime_error ("SSL/TLS not running on this connection");
768
+ return SslBox->GetPeerCert();
769
+ }
770
+ #endif
771
+
740
772
 
741
773
  /*****************************************
742
774
  ConnectionDescriptor::_DispatchCiphertext
743
775
  *****************************************/
776
+
744
777
  #ifdef WITH_SSL
745
778
  void ConnectionDescriptor::_DispatchCiphertext()
746
779
  {
data/ext/ed.h CHANGED
@@ -69,6 +69,10 @@ class EventableDescriptor: public Bindable_t
69
69
  virtual void StartTls() {}
70
70
  virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename) {}
71
71
 
72
+ #ifdef WITH_SSL
73
+ virtual X509 *GetPeerCert() {return NULL;}
74
+ #endif
75
+
72
76
  // Properties: return 0/1 to signify T/F, and handle the values
73
77
  // through arguments.
74
78
  virtual int GetCommInactivityTimeout (int *value) {return 0;}
@@ -101,6 +105,7 @@ class EventableDescriptor: public Bindable_t
101
105
  time_t LastRead;
102
106
  time_t LastWritten;
103
107
  bool bCallbackUnbind;
108
+ int UnbindReasonCode;
104
109
 
105
110
  #ifdef HAVE_EPOLL
106
111
  struct epoll_event EpollEvent;
@@ -163,6 +168,11 @@ class ConnectionDescriptor: public EventableDescriptor
163
168
 
164
169
  virtual void StartTls();
165
170
  virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename);
171
+
172
+ #ifdef WITH_SSL
173
+ virtual X509 *GetPeerCert();
174
+ #endif
175
+
166
176
  void SetServerMode() {bIsServer = true;}
167
177
 
168
178
  virtual bool GetPeername (struct sockaddr*);
@@ -197,6 +207,7 @@ class ConnectionDescriptor: public EventableDescriptor
197
207
  SslBox_t *SslBox;
198
208
  std::string CertChainFilename;
199
209
  std::string PrivateKeyFilename;
210
+ bool bHandshakeSignaled;
200
211
  #endif
201
212
  bool bIsServer;
202
213
 
@@ -209,6 +220,7 @@ class ConnectionDescriptor: public EventableDescriptor
209
220
  void _DispatchCiphertext();
210
221
  int _SendRawOutboundData (const char*, int);
211
222
  int _ReportErrorStatus();
223
+ void _CheckHandshakeStatus();
212
224
 
213
225
  };
214
226