Merge pull request #607 from sfackler/set-session
Logic to support client-side session reuse
This commit is contained in:
commit
d66d84b2f5
|
|
@ -77,8 +77,7 @@ matrix:
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- ./openssl/test/build.sh
|
- ./openssl/test/build.sh
|
||||||
- curl https://static.rust-lang.org/rustup.sh |
|
- rustup target add $TARGET || true
|
||||||
sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`
|
|
||||||
script:
|
script:
|
||||||
- ./openssl/test/run.sh
|
- ./openssl/test/run.sh
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1356,7 +1356,7 @@ pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -
|
||||||
|
|
||||||
#[cfg(not(any(ossl101, libressl)))]
|
#[cfg(not(any(ossl101, libressl)))]
|
||||||
pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long {
|
pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long {
|
||||||
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void)
|
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX,
|
pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX,
|
||||||
|
|
@ -1891,6 +1891,7 @@ extern {
|
||||||
client: *const c_uchar, client_len: c_uint) -> c_int;
|
client: *const c_uchar, client_len: c_uint) -> c_int;
|
||||||
pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint);
|
pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint);
|
||||||
pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION;
|
pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION;
|
||||||
|
pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int;
|
||||||
#[cfg(not(any(ossl101, libressl)))]
|
#[cfg(not(any(ossl101, libressl)))]
|
||||||
pub fn SSL_is_server(s: *mut SSL) -> c_int;
|
pub fn SSL_is_server(s: *mut SSL) -> c_int;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once, ONCE_INIT};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong};
|
use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong};
|
||||||
use libc::time_t;
|
use libc::time_t;
|
||||||
|
|
@ -500,7 +501,7 @@ pub struct SSL_SESSION {
|
||||||
verify_result: c_long,
|
verify_result: c_long,
|
||||||
timeout: c_long,
|
timeout: c_long,
|
||||||
time: time_t,
|
time: time_t,
|
||||||
references: c_int,
|
pub references: c_int,
|
||||||
cipher: *const c_void,
|
cipher: *const c_void,
|
||||||
cipher_id: c_ulong,
|
cipher_id: c_ulong,
|
||||||
ciphers: *mut c_void,
|
ciphers: *mut c_void,
|
||||||
|
|
@ -533,6 +534,7 @@ pub struct X509_VERIFY_PARAM {
|
||||||
pub enum X509_VERIFY_PARAM_ID {}
|
pub enum X509_VERIFY_PARAM_ID {}
|
||||||
pub enum PKCS12 {}
|
pub enum PKCS12 {}
|
||||||
|
|
||||||
|
pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8;
|
||||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||||
pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
|
pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
|
||||||
|
|
@ -565,6 +567,7 @@ pub const SSLEAY_DIR : c_int = 5;
|
||||||
|
|
||||||
pub const CRYPTO_LOCK_X509: c_int = 3;
|
pub const CRYPTO_LOCK_X509: c_int = 3;
|
||||||
pub const CRYPTO_LOCK_SSL_CTX: c_int = 12;
|
pub const CRYPTO_LOCK_SSL_CTX: c_int = 12;
|
||||||
|
pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14;
|
||||||
|
|
||||||
static mut MUTEXES: *mut Vec<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
|
static mut MUTEXES: *mut Vec<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
|
||||||
static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
|
static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
|
||||||
|
|
@ -622,11 +625,15 @@ fn set_id_callback() {}
|
||||||
// macros
|
// macros
|
||||||
|
|
||||||
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int {
|
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int {
|
||||||
::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int
|
::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
||||||
::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int
|
::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int {
|
||||||
|
::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once, ONCE_INIT};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong};
|
use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong};
|
||||||
#[cfg(not(ossl101))]
|
#[cfg(not(ossl101))]
|
||||||
|
|
@ -610,7 +611,7 @@ pub struct SSL_SESSION {
|
||||||
sess_cert: *mut c_void,
|
sess_cert: *mut c_void,
|
||||||
peer: *mut X509,
|
peer: *mut X509,
|
||||||
verify_result: c_long,
|
verify_result: c_long,
|
||||||
references: c_int,
|
pub references: c_int,
|
||||||
timeout: c_long,
|
timeout: c_long,
|
||||||
time: c_long,
|
time: c_long,
|
||||||
compress_meth: c_uint,
|
compress_meth: c_uint,
|
||||||
|
|
@ -678,6 +679,7 @@ pub struct X509_VERIFY_PARAM {
|
||||||
pub enum X509_VERIFY_PARAM_ID {}
|
pub enum X509_VERIFY_PARAM_ID {}
|
||||||
pub enum PKCS12 {}
|
pub enum PKCS12 {}
|
||||||
|
|
||||||
|
pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8;
|
||||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||||
#[cfg(ossl102)]
|
#[cfg(ossl102)]
|
||||||
|
|
@ -708,6 +710,7 @@ pub const SSLEAY_DIR : c_int = 5;
|
||||||
|
|
||||||
pub const CRYPTO_LOCK_X509: c_int = 3;
|
pub const CRYPTO_LOCK_X509: c_int = 3;
|
||||||
pub const CRYPTO_LOCK_SSL_CTX: c_int = 12;
|
pub const CRYPTO_LOCK_SSL_CTX: c_int = 12;
|
||||||
|
pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14;
|
||||||
|
|
||||||
static mut MUTEXES: *mut Vec<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
|
static mut MUTEXES: *mut Vec<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
|
||||||
static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
|
static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
|
||||||
|
|
@ -766,12 +769,16 @@ fn set_id_callback() {}
|
||||||
|
|
||||||
#[cfg(ossl102)]
|
#[cfg(ossl102)]
|
||||||
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int {
|
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int {
|
||||||
::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int
|
::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(ossl102)]
|
#[cfg(ossl102)]
|
||||||
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
||||||
::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int
|
::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int {
|
||||||
|
::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
|
|
||||||
|
|
@ -172,10 +172,12 @@ extern {
|
||||||
-> c_int;
|
-> c_int;
|
||||||
pub fn X509_up_ref(x: *mut X509) -> c_int;
|
pub fn X509_up_ref(x: *mut X509) -> c_int;
|
||||||
pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int;
|
pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int;
|
||||||
|
pub fn SSL_session_reused(ssl: *mut SSL) -> c_int;
|
||||||
pub fn SSL_SESSION_get_master_key(session: *const SSL_SESSION,
|
pub fn SSL_SESSION_get_master_key(session: *const SSL_SESSION,
|
||||||
out: *mut c_uchar,
|
out: *mut c_uchar,
|
||||||
outlen: size_t)
|
outlen: size_t)
|
||||||
-> size_t;
|
-> size_t;
|
||||||
|
pub fn SSL_SESSION_up_ref(ses: *mut SSL_SESSION) -> c_int;
|
||||||
pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION;
|
pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION;
|
||||||
pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
|
pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
|
||||||
pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX;
|
pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX;
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,7 @@ impl SslConnector {
|
||||||
pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||||
where S: Read + Write
|
where S: Read + Write
|
||||||
{
|
{
|
||||||
let mut ssl = try!(Ssl::new(&self.0));
|
try!(self.configure()).connect(domain, stream)
|
||||||
try!(ssl.set_hostname(domain));
|
|
||||||
try!(setup_verify(&mut ssl, domain));
|
|
||||||
|
|
||||||
ssl.connect(stream)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiates a client-side TLS session on a stream without performing hostname verification.
|
/// Initiates a client-side TLS session on a stream without performing hostname verification.
|
||||||
|
|
@ -113,7 +109,56 @@ impl SslConnector {
|
||||||
&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||||
where S: Read + Write
|
where S: Read + Write
|
||||||
{
|
{
|
||||||
try!(Ssl::new(&self.0)).connect(stream)
|
try!(self.configure())
|
||||||
|
.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a structure allowing for configuration of a single TLS session before connection.
|
||||||
|
pub fn configure(&self) -> Result<ConnectConfiguration, ErrorStack> {
|
||||||
|
Ssl::new(&self.0).map(ConnectConfiguration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type which allows for configuration of a client-side TLS session before connection.
|
||||||
|
pub struct ConnectConfiguration(Ssl);
|
||||||
|
|
||||||
|
impl ConnectConfiguration {
|
||||||
|
/// Returns a shared reference to the inner `Ssl`.
|
||||||
|
pub fn ssl(&self) -> &Ssl {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the inner `Ssl`.
|
||||||
|
pub fn ssl_mut(&mut self) -> &mut Ssl {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initiates a client-side TLS session on a stream.
|
||||||
|
///
|
||||||
|
/// The domain is used for SNI and hostname verification.
|
||||||
|
pub fn connect<S>(mut self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||||
|
where S: Read + Write
|
||||||
|
{
|
||||||
|
try!(self.0.set_hostname(domain));
|
||||||
|
try!(setup_verify(&mut self.0, domain));
|
||||||
|
|
||||||
|
self.0.connect(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initiates a client-side TLS session on a stream without performing hostname verification.
|
||||||
|
///
|
||||||
|
/// The verification configuration of the connector's `SslContext` is not overridden.
|
||||||
|
///
|
||||||
|
/// # Warning
|
||||||
|
///
|
||||||
|
/// You should think very carefully before you use this method. If hostname verification is not
|
||||||
|
/// used, *any* valid certificate for *any* site will be trusted for use from any other. This
|
||||||
|
/// introduces a significant vulnerability to man-in-the-middle attacks.
|
||||||
|
pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication<S>(
|
||||||
|
self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||||
|
where S: Read + Write
|
||||||
|
{
|
||||||
|
self.0.connect(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ use libc::{c_int, c_void, c_long, c_ulong};
|
||||||
use libc::{c_uchar, c_uint};
|
use libc::{c_uchar, c_uint};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
|
|
@ -1161,6 +1162,32 @@ foreign_type! {
|
||||||
pub struct SslSessionRef;
|
pub struct SslSessionRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for SslSession {}
|
||||||
|
unsafe impl Send for SslSession {}
|
||||||
|
|
||||||
|
impl Clone for SslSession {
|
||||||
|
fn clone(&self) -> SslSession {
|
||||||
|
self.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Borrow<SslSessionRef> for SslSession {
|
||||||
|
fn borrow(&self) -> &SslSessionRef {
|
||||||
|
&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToOwned for SslSessionRef {
|
||||||
|
type Owned = SslSession;
|
||||||
|
|
||||||
|
fn to_owned(&self) -> SslSession {
|
||||||
|
unsafe {
|
||||||
|
compat::SSL_SESSION_up_ref(self.as_ptr());
|
||||||
|
SslSession(self.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SslSessionRef {
|
impl SslSessionRef {
|
||||||
/// Returns the SSL session ID.
|
/// Returns the SSL session ID.
|
||||||
pub fn id(&self) -> &[u8] {
|
pub fn id(&self) -> &[u8] {
|
||||||
|
|
@ -1508,6 +1535,23 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the session to be used.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller of this method is responsible for ensuring that the session is associated
|
||||||
|
/// with the same `SslContext` as this `Ssl`.
|
||||||
|
pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
|
||||||
|
cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the session provided to `set_session` was successfully reused.
|
||||||
|
pub fn session_reused(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
ffi::SSL_session_reused(self.as_ptr()) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the status response a client wishes the server to reply with.
|
/// Sets the status response a client wishes the server to reply with.
|
||||||
pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
|
pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -1918,7 +1962,7 @@ mod compat {
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref,
|
pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref,
|
||||||
SSL_SESSION_get_master_key, SSL_is_server};
|
SSL_SESSION_get_master_key, SSL_is_server, SSL_SESSION_up_ref};
|
||||||
|
|
||||||
pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
|
pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
|
||||||
ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX,
|
ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX,
|
||||||
|
|
@ -2014,4 +2058,13 @@ mod compat {
|
||||||
pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
|
pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
|
||||||
(*s).server
|
(*s).server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
|
||||||
|
ffi::CRYPTO_add_lock(&mut (*ses).references,
|
||||||
|
1,
|
||||||
|
ffi::CRYPTO_LOCK_SSL_CTX,
|
||||||
|
"mod.rs\0".as_ptr() as *const _,
|
||||||
|
line!() as libc::c_int);
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue