aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-03-05 21:36:11 +0000
committergotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-03-05 21:36:11 +0000
commita9fb0817a15469f0572cd3b8637243daecfe168e (patch)
tree146a5c28bcd348a1ea3333e9b0ae59d58ff078d9
parent4b0f7cecc41ec1ae015eed42bd0b82538e8b9408 (diff)
downloadruby-a9fb0817a15469f0572cd3b8637243daecfe168e.tar.gz
* ext/openssl/ossl_ssl.c (ossl_start_ssl): should wait for that
the underlying IO become readable or writable if the error was SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. [ruby-dev:25795] * ext/openssl/ossl_ssl.c (ossl_ssl_read, ossl_ssl_write): ditto. * ext/openssl/lib/openssl/buffering.rb (Buffering#consume_rbuf): pointless eof flag resetting is deleted. (Buffering#read): should return an empty string if the specified size is zero. (Buffering#readpartial): new method. (Buffering#readline): fix typo. (Buffering#getc): return the first character of string correctly. (Buffering#readchar): fix typo. (Buffering#eof?): should read again it the input buffer is empty. (Buffering#do_write): should rescue Errno::EAGAIN. (Buffering#puts): use "\n" as the output field separator. * ext/openssl/extconf.rb: get rid of GNUmakefile generation. * text/openssl/test_pair.rb: test for IO like methods. * test/ruby/ut_eof.rb: test about empty file. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8081 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog26
-rw-r--r--ext/openssl/extconf.rb28
-rw-r--r--ext/openssl/lib/openssl/buffering.rb55
-rw-r--r--ext/openssl/ossl_ssl.c55
-rw-r--r--test/openssl/test_pair.rb332
-rw-r--r--test/ruby/ut_eof.rb26
6 files changed, 461 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog
index 22f6812540..21414ece3d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+Sun Mar 6 06:34:31 2005 GOTOU Yuuzou <gotoyuzo@notwork.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_start_ssl): should wait for that
+ the underlying IO become readable or writable if the error was
+ SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. [ruby-dev:25795]
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_read, ossl_ssl_write): ditto.
+
+ * ext/openssl/lib/openssl/buffering.rb
+ (Buffering#consume_rbuf): pointless eof flag resetting is deleted.
+ (Buffering#read): should return an empty string if the specified
+ size is zero.
+ (Buffering#readpartial): new method.
+ (Buffering#readline): fix typo.
+ (Buffering#getc): return the first character of string correctly.
+ (Buffering#readchar): fix typo.
+ (Buffering#eof?): should read again it the input buffer is empty.
+ (Buffering#do_write): should rescue Errno::EAGAIN.
+ (Buffering#puts): use "\n" as the output field separator.
+
+ * ext/openssl/extconf.rb: get rid of GNUmakefile generation.
+
+ * text/openssl/test_pair.rb: test for IO like methods.
+
+ * test/ruby/ut_eof.rb: test about empty file.
+
Sat Mar 5 17:48:31 2005 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
* dir.c (rb_glob): fixed mismatch of argument.
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index d587116c82..4517ec82fb 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -113,33 +113,5 @@ have_struct_member("EVP_CIPHER_CTX", "engine", "openssl/evp.h")
have_struct_member("X509_ATTRIBUTE", "single", "openssl/x509.h")
message "=== Checking done. ===\n"
-$distcleanfiles << "GNUmakefile" << "dep"
create_makefile("openssl")
-if /gcc/ =~ CONFIG["CC"]
- File.open("GNUmakefile", "w") {|f|
- f.print <<EOD
-include Makefile
-
-SRCS = $(OBJS:.o=.c)
-
-test-link: $(OBJS)
- $(CC) $(DLDFLAGS) #{OUTFLAG}.testlink $(OBJS) $(LIBPATH) $(LIBS) $(LOCAL_LIBS)
- @$(RM) .testlink
- @echo "Done."
-
-dep:
- $(CC) $(CFLAGS) $(CPPFLAGS) -c $(SRCS) -MM | \\
- $(RUBY) -p -e 'BEGIN{S = []' \\
- -e 'while !ARGV.empty? and /^(\\w+)=(.*)/ =~ ARGV[0]' \\
- -e 'S << [/\#{Regexp.quote($$2)}\\//, "$$(\#{$$1})/"]' \\
- -e 'ARGV.shift' \\
- -e 'end' \\
- -e '}' -e 'S.each(&method(:gsub!))' -- \\
- 'topdir=$(topdir)' 'srcdir=$(srcdir)' 'hdrdir=$(hdrdir)' \\
- > dep
-
-include dep
-EOD
- }
-end
message "Done.\n"
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index 7ad12d7203..39c442bfd1 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -41,7 +41,6 @@ module Buffering
def consume_rbuff(size=nil)
if @rbuffer.size == 0
- @eof = nil
nil
else
size = @rbuffer.size unless size
@@ -54,6 +53,14 @@ module Buffering
public
def read(size=nil, buf=nil)
+ if size == 0
+ if buf
+ buf.clear
+ return buf
+ else
+ return ""
+ end
+ end
fill_rbuff unless defined? @rbuffer
@eof ||= nil
until @eof
@@ -68,6 +75,31 @@ module Buffering
(size && ret.empty?) ? nil : ret
end
+ def readpartial(maxlen, buf=nil)
+ if maxlen == 0
+ if buf
+ buf.clear
+ return buf
+ else
+ return ""
+ end
+ end
+ if !defined?(@rbuffer) || @rbuffer.size == 0
+ begin
+ return sysread(maxlen, buf)
+ rescue Errno::EAGAIN
+ retry
+ end
+ end
+ ret = consume_rbuff(maxlen)
+ if buf
+ buf.replace(ret)
+ ret = buf
+ end
+ raise EOFError if ret.empty?
+ ret
+ end
+
def gets(eol=$/)
fill_rbuff unless defined? @rbuffer
idx = @rbuffer.index(eol)
@@ -101,13 +133,13 @@ module Buffering
end
def readline(eol=$/)
- raise EOFErorr if eof?
+ raise EOFError if eof?
gets(eol)
end
def getc
c = read(1)
- c ? c.to_i : nil
+ c ? c[0] : nil
end
def each_byte
@@ -117,7 +149,7 @@ module Buffering
end
def readchar
- raise EOFErorr if eof?
+ raise EOFError if eof?
getc
end
@@ -127,6 +159,7 @@ module Buffering
def eof?
@eof ||= nil
+ fill_rbuff if !@eof && (!defined?(@rbuffer) || @rbuffer.size == 0)
@eof && @rbuffer.size == 0
end
alias eof eof?
@@ -144,7 +177,12 @@ module Buffering
remain = idx ? idx + $/.size : @wbuffer.length
nwritten = 0
while remain > 0
- nwrote = syswrite(@wbuffer[nwritten,remain])
+ str = @wbuffer[nwritten,remain]
+ begin
+ nwrote = syswrite(str)
+ rescue Errno::EAGAIN
+ retry
+ end
remain -= nwrote
nwritten += nwrote
end
@@ -166,10 +204,13 @@ module Buffering
def puts(*args)
s = ""
+ if args.empty?
+ s << "\n"
+ end
args.each{|arg|
s << arg.to_s
- unless /#{$/}\z/o =~ s
- s << $/
+ if $/ && /\n\z/ !~ s
+ s << "\n"
end
}
do_write(s)
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index e85430e859..323dc97f83 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -433,52 +433,49 @@ ossl_ssl_setup(VALUE self)
return Qtrue;
}
-static void
-ossl_start_ssl(SSL *ssl, int (*func)())
+static VALUE
+ossl_start_ssl(VALUE self, int (*func)())
{
+ SSL *ssl;
+ OpenFile *fptr;
+ VALUE cb;
int ret;
+ Data_Get_Struct(self, SSL, ssl);
+ GetOpenFile(ossl_ssl_get_io(self), fptr);
+ cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
+ SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
for(;;){
if((ret = func(ssl)) > 0) break;
switch(SSL_get_error(ssl, ret)){
case SSL_ERROR_WANT_WRITE:
+ rb_io_wait_writable(fptr->fd);
+ continue;
case SSL_ERROR_WANT_READ:
- rb_thread_schedule();
- continue;
+ rb_io_wait_readable(fptr->fd);
+ continue;
+ case SSL_ERROR_SYSCALL:
+ rb_sys_fail(0);
default:
ossl_raise(eSSLError, NULL);
}
}
+
+ return self;
}
static VALUE
ossl_ssl_connect(VALUE self)
{
- SSL *ssl;
- VALUE cb;
-
ossl_ssl_setup(self);
- Data_Get_Struct(self, SSL, ssl);
- cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
- SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
- ossl_start_ssl(ssl, SSL_connect);
-
- return self;
+ return ossl_start_ssl(self, SSL_connect);
}
static VALUE
ossl_ssl_accept(VALUE self)
{
- SSL *ssl;
- VALUE cb;
-
ossl_ssl_setup(self);
- Data_Get_Struct(self, SSL, ssl);
- cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
- SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
- ossl_start_ssl(ssl, SSL_accept);
-
- return self;
+ return ossl_start_ssl(self, SSL_accept);
}
static VALUE
@@ -512,8 +509,10 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self)
case SSL_ERROR_ZERO_RETURN:
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
+ rb_io_wait_writable(fptr->fd);
+ continue;
case SSL_ERROR_WANT_READ:
- rb_thread_schedule();
+ rb_io_wait_readable(fptr->fd);
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -542,9 +541,11 @@ ossl_ssl_write(VALUE self, VALUE str)
{
SSL *ssl;
int nwrite = 0;
+ OpenFile *fptr;
StringValue(str);
Data_Get_Struct(self, SSL, ssl);
+ GetOpenFile(ossl_ssl_get_io(self), fptr);
if (ssl) {
for (;;){
@@ -553,11 +554,13 @@ ossl_ssl_write(VALUE self, VALUE str)
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_WANT_WRITE:
+ rb_io_wait_writable(fptr->fd);
+ continue;
case SSL_ERROR_WANT_READ:
- rb_thread_schedule();
- continue;
+ rb_io_wait_readable(fptr->fd);
+ continue;
case SSL_ERROR_SYSCALL:
- rb_eof_error();
+ rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_write:");
}
diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb
new file mode 100644
index 0000000000..7dd658b825
--- /dev/null
+++ b/test/openssl/test_pair.rb
@@ -0,0 +1,332 @@
+begin
+ require "openssl"
+rescue LoadError
+end
+require 'test/unit'
+
+if defined?(OpenSSL)
+
+require 'socket'
+dir = File.expand_path(__FILE__)
+2.times {dir = File.dirname(dir)}
+$:.replace([File.join(dir, "ruby")] | $:)
+require 'ut_eof'
+
+module SSLPair
+ def server
+ host = "127.0.0.1"
+ port = 0
+ key = OpenSSL::PKey::RSA.new(512)
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 0
+ name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + 3600
+ cert.public_key = key.public_key
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier","hash"),
+ ef.create_extension("extendedKeyUsage","serverAuth"),
+ ef.create_extension("keyUsage",
+ "keyEncipherment,dataEncipherment,digitalSignature")
+ ]
+ ef.issuer_certificate = cert
+ cert.add_extension ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.sign(key, OpenSSL::Digest::SHA1.new)
+ ctx = OpenSSL::SSL::SSLContext.new()
+ ctx.key = key
+ ctx.cert = cert
+ tcps = TCPServer.new(host, port)
+ ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
+ return ssls
+ end
+
+ def client(port)
+ host = "127.0.0.1"
+ ctx = OpenSSL::SSL::SSLContext.new()
+ s = TCPSocket.new(host, port)
+ ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
+ ssl.connect
+ ssl.sync_close = true
+ ssl
+ end
+
+ def ssl_pair
+ ssls = server
+ th = Thread.new {
+ ns = ssls.accept
+ ssls.close
+ ns
+ }
+ port = ssls.to_io.addr[1]
+ c = client(port)
+ s = th.value
+ if block_given?
+ begin
+ yield c, s
+ ensure
+ c.close unless c.closed?
+ s.close unless s.closed?
+ end
+ else
+ return c, s
+ end
+ end
+end
+
+class OpenSSL::TestEOF1 < Test::Unit::TestCase
+ include TestEOF
+ include SSLPair
+
+ def open_file(content)
+ s1, s2 = ssl_pair
+ Thread.new { s2 << content; s2.close }
+ yield s1
+ end
+end
+
+class OpenSSL::TestEOF2 < Test::Unit::TestCase
+ include TestEOF
+ include SSLPair
+
+ def open_file(content)
+ s1, s2 = ssl_pair
+ Thread.new { s1 << content; s1.close }
+ yield s2
+ end
+end
+
+class OpenSSL::TestPair < Test::Unit::TestCase
+ include SSLPair
+
+ def test_getc
+ ssl_pair {|s1, s2|
+ s1 << "a"
+ assert_equal(?a, s2.getc)
+ }
+ end
+
+ def test_readpartial
+ ssl_pair {|s1, s2|
+ s2.write "a\nbcd"
+ assert_equal("a\n", s1.gets)
+ assert_equal("bcd", s1.readpartial(10))
+ s2.write "efg"
+ assert_equal("efg", s1.readpartial(10))
+ s2.close
+ assert_raise(EOFError) { s1.readpartial(10) }
+ assert_raise(EOFError) { s1.readpartial(10) }
+ assert_equal("", s1.readpartial(0))
+ }
+ end
+
+ def test_readall
+ ssl_pair {|s1, s2|
+ s2.close
+ assert_equal("", s1.read)
+ }
+ end
+
+ def test_readline
+ ssl_pair {|s1, s2|
+ s2.close
+ assert_raise(EOFError) { s1.readline }
+ }
+ end
+
+ def test_puts_meta
+ ssl_pair {|s1, s2|
+ begin
+ old = $/
+ $/ = '*'
+ s1.puts 'a'
+ ensure
+ $/ = old
+ end
+ s1.close
+ assert_equal("a\n", s2.read)
+ }
+ end
+
+ def test_puts_empty
+ ssl_pair {|s1, s2|
+ s1.puts
+ s1.close
+ assert_equal("\n", s2.read)
+ }
+ end
+
+end
+
+end
+begin
+ require "openssl"
+rescue LoadError
+end
+require 'test/unit'
+
+if defined?(OpenSSL)
+
+require 'socket'
+dir = File.expand_path(__FILE__)
+2.times {dir = File.dirname(dir)}
+$:.replace([File.join(dir, "ruby")] | $:)
+require 'ut_eof'
+
+module SSLPair
+ def server
+ host = "127.0.0.1"
+ port = 0
+ key = OpenSSL::PKey::RSA.new(512)
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 0
+ name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + 3600
+ cert.public_key = key.public_key
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier","hash"),
+ ef.create_extension("extendedKeyUsage","serverAuth"),
+ ef.create_extension("keyUsage",
+ "keyEncipherment,dataEncipherment,digitalSignature")
+ ]
+ ef.issuer_certificate = cert
+ cert.add_extension ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.sign(key, OpenSSL::Digest::SHA1.new)
+ ctx = OpenSSL::SSL::SSLContext.new()
+ ctx.key = key
+ ctx.cert = cert
+ tcps = TCPServer.new(host, port)
+ ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
+ return ssls
+ end
+
+ def client(port)
+ host = "127.0.0.1"
+ ctx = OpenSSL::SSL::SSLContext.new()
+ s = TCPSocket.new(host, port)
+ ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
+ ssl.connect
+ ssl.sync_close = true
+ ssl
+ end
+
+ def ssl_pair
+ ssls = server
+ th = Thread.new {
+ ns = ssls.accept
+ ssls.close
+ ns
+ }
+ port = ssls.to_io.addr[1]
+ c = client(port)
+ s = th.value
+ if block_given?
+ begin
+ yield c, s
+ ensure
+ c.close unless c.closed?
+ s.close unless s.closed?
+ end
+ else
+ return c, s
+ end
+ end
+end
+
+class OpenSSL::TestEOF1 < Test::Unit::TestCase
+ include TestEOF
+ include SSLPair
+
+ def open_file(content)
+ s1, s2 = ssl_pair
+ Thread.new { s2 << content; s2.close }
+ yield s1
+ end
+end
+
+class OpenSSL::TestEOF2 < Test::Unit::TestCase
+ include TestEOF
+ include SSLPair
+
+ def open_file(content)
+ s1, s2 = ssl_pair
+ Thread.new { s1 << content; s1.close }
+ yield s2
+ end
+end
+
+class OpenSSL::TestPair < Test::Unit::TestCase
+ include SSLPair
+
+ def test_getc
+ ssl_pair {|s1, s2|
+ s1 << "a"
+ assert_equal(?a, s2.getc)
+ }
+ end
+
+ def test_readpartial
+ ssl_pair {|s1, s2|
+ s2.write "a\nbcd"
+ assert_equal("a\n", s1.gets)
+ assert_equal("bcd", s1.readpartial(10))
+ s2.write "efg"
+ assert_equal("efg", s1.readpartial(10))
+ s2.close
+ assert_raise(EOFError) { s1.readpartial(10) }
+ assert_raise(EOFError) { s1.readpartial(10) }
+ assert_equal("", s1.readpartial(0))
+ }
+ end
+
+ def test_readall
+ ssl_pair {|s1, s2|
+ s2.close
+ assert_equal("", s1.read)
+ }
+ end
+
+ def test_readline
+ ssl_pair {|s1, s2|
+ s2.close
+ assert_raise(EOFError) { s1.readline }
+ }
+ end
+
+ def test_puts_meta
+ ssl_pair {|s1, s2|
+ begin
+ old = $/
+ $/ = '*'
+ s1.puts 'a'
+ ensure
+ $/ = old
+ end
+ s1.close
+ assert_equal("a\n", s2.read)
+ }
+ end
+
+ def test_puts_empty
+ ssl_pair {|s1, s2|
+ s1.puts
+ s1.close
+ assert_equal("\n", s2.read)
+ }
+ end
+
+end
+
+end
diff --git a/test/ruby/ut_eof.rb b/test/ruby/ut_eof.rb
index bf03771fc3..9aa020685b 100644
--- a/test/ruby/ut_eof.rb
+++ b/test/ruby/ut_eof.rb
@@ -83,6 +83,32 @@ module TestEOF
}
end
+ def test_eof_2
+ open_file("") {|f|
+ assert_equal("", f.read)
+ assert(f.eof?)
+ }
+ end
+
+ def test_eof_3
+ open_file("") {|f|
+ assert(f.eof?)
+ }
+ end
+
+ def test_eof_2
+ open_file("") {|f|
+ assert_equal("", f.read)
+ assert(f.eof?)
+ }
+ end
+
+ def test_eof_3
+ open_file("") {|f|
+ assert(f.eof?)
+ }
+ end
+
module Seek
def open_file_seek(content, pos)
open_file(content) do |f|