ext/rubysl/openssl/ossl_ssl.c in rubysl-openssl-2.1.0 vs ext/rubysl/openssl/ossl_ssl.c in rubysl-openssl-2.2.0
- old
+ new
@@ -27,10 +27,13 @@
VALUE mSSL;
VALUE eSSLError;
VALUE cSSLContext;
VALUE cSSLSocket;
+static VALUE eSSLErrorWaitReadable;
+static VALUE eSSLErrorWaitWritable;
+
#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v))
#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v))
#define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v))
#define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v))
#define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v))
@@ -98,10 +101,12 @@
"sync_close",
};
ID ID_callback_state;
+static VALUE sym_exception;
+
/*
* SSLContext class
*/
struct {
const char *name;
@@ -416,11 +421,11 @@
if (state) {
rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
}
/*
- * return 0 which means to OpenSSL that the the session is still
+ * return 0 which means to OpenSSL that the session is still
* valid (since we created Ruby Session object) and was not freed by us
* with SSL_SESSION_free(). Call SSLContext#remove_session(sess) in
* session_get_cb block if you don't want OpenSSL to cache the session
* internally.
*/
@@ -470,11 +475,11 @@
*/
}
}
static VALUE
-ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
+ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
{
X509 *x509;
SSL_CTX *ctx;
Data_Get_Struct(arg, SSL_CTX, ctx);
@@ -711,11 +716,11 @@
val = ossl_sslctx_get_client_ca(self);
if(!NIL_P(val)){
if(TYPE(val) == T_ARRAY){
for(i = 0; i < RARRAY_LEN(val); i++){
- client_ca = GetX509CertPtr(rb_ary_entry(val, i));
+ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
/* Copies X509_NAME => FREE it. */
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
}
@@ -1090,10 +1095,11 @@
}
/*
* SSLSocket class
*/
+#ifndef OPENSSL_NO_SOCK
static void
ossl_ssl_shutdown(SSL *ssl)
{
int i, rc;
@@ -1103,11 +1109,11 @@
for (i = 0; i < 4; ++i) {
/*
* Ignore the case SSL_shutdown returns -1. Empty handshake_func
* must not happen.
*/
- if (rc = SSL_shutdown(ssl))
+ if ((rc = SSL_shutdown(ssl)))
break;
}
SSL_clear(ssl);
ERR_clear_error();
}
@@ -1129,11 +1135,11 @@
* call-seq:
* SSLSocket.new(io) => aSSLSocket
* SSLSocket.new(io, ctx) => aSSLSocket
*
* Creates a new SSL socket from +io+ which must be a real ruby object (not an
- * IO-like object that responds to read/write.
+ * IO-like object that responds to read/write).
*
* If +ctx+ is provided the SSL Sockets initial params will be taken from
* the context.
*
* The OpenSSL::Buffering module provides additional IO methods.
@@ -1227,22 +1233,20 @@
static void
write_would_block(int nonblock)
{
if (nonblock) {
- VALUE exc = ossl_exc_new(eSSLError, "write would block");
- rb_extend_object(exc, rb_mWaitWritable);
+ VALUE exc = ossl_exc_new(eSSLErrorWaitWritable, "write would block");
rb_exc_raise(exc);
}
}
static void
read_would_block(int nonblock)
{
if (nonblock) {
- VALUE exc = ossl_exc_new(eSSLError, "read would block");
- rb_extend_object(exc, rb_mWaitReadable);
+ VALUE exc = ossl_exc_new(eSSLErrorWaitReadable, "read would block");
rb_exc_raise(exc);
}
}
static VALUE
@@ -1369,14 +1373,20 @@
static VALUE
ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
{
SSL *ssl;
int ilen, nread = 0;
+ int no_exception = 0;
VALUE len, str;
rb_io_t *fptr;
+ VALUE opts = Qnil;
- rb_scan_args(argc, argv, "11", &len, &str);
+ rb_scan_args(argc, argv, "11:", &len, &str, &opts);
+
+ if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+ no_exception = 1;
+
ilen = NUM2INT(len);
if(NIL_P(str)) str = rb_str_new(0, ilen);
else{
StringValue(str);
rb_str_modify(str);
@@ -1393,21 +1403,27 @@
nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
switch(ssl_get_error(ssl, nread)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
+ if (no_exception) { return Qnil; }
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
+ if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
+ if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
- if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+ if(ERR_peek_error() == 0 && nread == 0) {
+ if (no_exception) { return Qnil; }
+ rb_eof_error();
+ }
rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_read");
}
}
@@ -1441,13 +1457,15 @@
/*
* call-seq:
* ssl.sysread_nonblock(length) => string
* ssl.sysread_nonblock(length, buffer) => buffer
+ * ssl.sysread_nonblock(length[, buffer [, opts]) => buffer
*
* A non-blocking version of #sysread. Raises an SSLError if reading would
- * block.
+ * block. If "exception: false" is passed, this method returns a symbol of
+ * :wait_readable, :wait_writable, or nil, rather than raising an exception.
*
* Reads +length+ bytes from the SSL connection. If a pre-allocated +buffer+
* is provided the data will be written into it.
*/
static VALUE
@@ -1455,11 +1473,11 @@
{
return ossl_ssl_read_internal(argc, argv, self, 1);
}
static VALUE
-ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
+ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception)
{
SSL *ssl;
int nwrite = 0;
rb_io_t *fptr;
@@ -1472,14 +1490,16 @@
nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
switch(ssl_get_error(ssl, nwrite)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_WANT_WRITE:
+ if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
+ if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if (errno) rb_sys_fail(0);
@@ -1505,24 +1525,33 @@
* Writes +string+ to the SSL connection.
*/
static VALUE
ossl_ssl_write(VALUE self, VALUE str)
{
- return ossl_ssl_write_internal(self, str, 0);
+ return ossl_ssl_write_internal(self, str, 0, 0);
}
/*
* call-seq:
* ssl.syswrite_nonblock(string) => Integer
*
* Writes +string+ to the SSL connection in a non-blocking manner. Raises an
* SSLError if writing would block.
*/
static VALUE
-ossl_ssl_write_nonblock(VALUE self, VALUE str)
+ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)
{
- return ossl_ssl_write_internal(self, str, 1);
+ VALUE str;
+ VALUE opts = Qnil;
+ int no_exception = 0;
+
+ rb_scan_args(argc, argv, "1:", &str, &opts);
+
+ if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+ no_exception = 1;
+
+ return ossl_ssl_write_internal(self, str, 1, no_exception);
}
/*
* call-seq:
* ssl.sysclose => nil
@@ -1631,11 +1660,11 @@
return ary;
}
/*
* call-seq:
-* ssl.version => String
+* ssl.ssl_version => String
*
* Returns a String representing the SSL/TLS version that was negotiated
* for the connection, for example "TLSv1.2".
*/
static VALUE
@@ -1792,11 +1821,11 @@
ca = SSL_get_client_CA_list(ssl);
return ossl_x509name_sk2ary(ca);
}
-#ifdef HAVE_OPENSSL_NPN_NEGOTIATED
+# ifdef HAVE_OPENSSL_NPN_NEGOTIATED
/*
* call-seq:
* ssl.npn_protocol => String
*
* Returns the protocol string that was finally selected by the client
@@ -1815,11 +1844,12 @@
if (!outlen)
return Qnil;
else
return rb_str_new((const char *) out, outlen);
}
-#endif
+# endif
+#endif /* !defined(OPENSSL_NO_SOCK) */
void
Init_ossl_ssl()
{
int i;
@@ -1850,10 +1880,14 @@
/* Document-class: OpenSSL::SSL::SSLError
*
* Generic error class raised by SSLSocket and SSLContext.
*/
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
+ eSSLErrorWaitReadable = rb_define_class_under(mSSL, "SSLErrorWaitReadable", eSSLError);
+ rb_include_module(eSSLErrorWaitReadable, rb_mWaitReadable);
+ eSSLErrorWaitWritable = rb_define_class_under(mSSL, "SSLErrorWaitWritable", eSSLError);
+ rb_include_module(eSSLErrorWaitWritable, rb_mWaitWritable);
Init_ossl_ssl_session();
/* Document-class: OpenSSL::SSL::SSLContext
*
@@ -1968,11 +2002,11 @@
*/
rb_attr(cSSLContext, rb_intern("tmp_dh_callback"), 1, 1, Qfalse);
/*
* Sets the context in which a session can be reused. This allows
- * sessions for multiple applications to be distinguished, for exapmle, by
+ * sessions for multiple applications to be distinguished, for example, by
* name.
*/
rb_attr(cSSLContext, rb_intern("session_id_context"), 1, 1, Qfalse);
/*
@@ -2142,10 +2176,13 @@
* The following attributes are available but don't show up in rdoc.
* * io, context, sync_close
*
*/
cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
+#ifdef OPENSSL_NO_SOCK
+ rb_define_method(cSSLSocket, "initialize", rb_notimplement, -1);
+#else
rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
for(i = 0; i < numberof(ossl_ssl_attr_readers); i++)
rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse);
for(i = 0; i < numberof(ossl_ssl_attrs); i++)
rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse);
@@ -2156,11 +2193,11 @@
rb_define_method(cSSLSocket, "accept", ossl_ssl_accept, 0);
rb_define_method(cSSLSocket, "accept_nonblock", ossl_ssl_accept_nonblock, 0);
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1);
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
- rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1);
+ rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, -1);
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0);
rb_define_method(cSSLSocket, "ssl_version", ossl_ssl_get_version, 0);
@@ -2170,12 +2207,13 @@
rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0);
/* implementation of OpenSSL::SSL::SSLSocket#session is in lib/openssl/ssl.rb */
rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1);
rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0);
-#ifdef HAVE_OPENSSL_NPN_NEGOTIATED
+# ifdef HAVE_OPENSSL_NPN_NEGOTIATED
rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0);
+# endif
#endif
#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2NUM(SSL_##x))
ossl_ssl_def_const(VERIFY_NONE);
@@ -2228,6 +2266,8 @@
#endif
ossl_ssl_def_const(OP_PKCS1_CHECK_1);
ossl_ssl_def_const(OP_PKCS1_CHECK_2);
ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+
+ sym_exception = ID2SYM(rb_intern("exception"));
}