#![allow(
clippy::unreadable_literal,
clippy::upper_case_acronyms,
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
overflowing_literals,
unused_variables,
unused_assignments
)]
extern crate libloading;
use std::convert::From;
use std::env;
use libc::c_void;
use libloading::{Library, Symbol};
use crate::bcossdk::bcoschannelclient::IBcosChannel;
use crate::bcossdk::bcosclientconfig::{BcosCryptoKind, ChannelConfig};
use crate::bcossdk::bufferqueue::BufferQueue;
use crate::bcossdk::channelpack::ChannelPack;
use crate::bcossdk::commonutil::is_windows;
use crate::bcossdk::kisserror::{KissErrKind, KissError};
type FN_SSOCK_CREATE = fn() -> *mut ::libc::c_void;
type FN_SSOCK_FINISH = fn(*mut ::libc::c_void);
type FN_SSOCK_RELEASE = fn(*mut ::libc::c_void);
type FN_SSOCK_INIT = fn(
p: *mut ::libc::c_void,
ca: *const u8,
sdk: *const u8,
key: *const u8,
ensdk: *const u8,
enkey: *const u8,
) -> i32;
type FN_SSOCK_SET_ECHO_MODE = fn(*mut ::libc::c_void, i32);
type FUNC_SSOCK_TRY_CONNECT = fn(*mut c_void, host: *const u8, port: i32) -> i32;
type FUNC_SSOCK_SEND = fn(*mut c_void, buffer: *const u8, len: i32) -> i32;
type FUNC_SSOCK_RECV = fn(*mut c_void, buffer: *mut u8, size: i32) -> i32;
pub fn lib_usage_msg() -> String {
let msg: String = r###"
此版本的tls链接依赖tassl动态库和c/c++原生代码实现,正常运行的注意点:
1)所有符合当前操作系统的动态库齐备。
2)动态库放于和目标运行程序相同的目录,或当前操作系统寻址加载动态库的目录。
3)如有版本出入,可能需要重新编译tassl库和c/c++原生代码。
具体参见“native_ssock_lib”的readme.md(本项目readme有连接)
"###
.to_string();
msg
}
fn rzero(s: &String) -> String {
let mut n = s.clone();
n.push('\0');
n
}
#[derive(Debug)]
pub struct SSockNativeLib {
pub pssock: *mut libc::c_void,
pub nativelib: Library,
}
impl SSockNativeLib {
pub fn close(&mut self) {}
}
#[derive(Debug)]
pub struct BcosNativeTlsClient {
pub ssocklib: Option<SSockNativeLib>,
pub config: ChannelConfig,
pub bufferqueue: BufferQueue,
pub is_valid: bool,
pub is_connect: bool,
pub channelpackpool: Vec<ChannelPack>, }
impl IBcosChannel for BcosNativeTlsClient {
fn connect(&mut self) -> Result<i32, KissError> {
unsafe {
let func_connect: Symbol<FUNC_SSOCK_TRY_CONNECT> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_try_connect")
.unwrap();
let r = func_connect(
self.ssocklib.as_ref().unwrap().pssock,
rzero(&self.config.ip).as_ptr(),
self.config.port as i32,
);
if r < 0 {
return kisserr!(KissErrKind::ENetwork, "tls connect error {}", r);
}
Ok(r)
}
}
fn send(&mut self, sendbuff: &Vec<u8>) -> Result<i32, KissError> {
unsafe {
let func_send: Symbol<FUNC_SSOCK_SEND> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_send")
.unwrap();
let r = func_send(
self.ssocklib.as_ref().unwrap().pssock,
sendbuff.as_ptr(),
sendbuff.len() as i32,
);
if r < 0 {
return kisserr!(KissErrKind::ENetwork, "send err {}", r);
}
Ok(r)
}
}
fn recv(&mut self) -> Result<Vec<u8>, KissError> {
unsafe {
let func_recv: Symbol<FUNC_SSOCK_SEND> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_recv")
.unwrap();
let size: usize = 1024 * 10;
let mut recvbuffer: Vec<u8> = Vec::with_capacity(size);
let pdst = recvbuffer.as_mut_ptr();
let r = func_recv(self.ssocklib.as_ref().unwrap().pssock, pdst, size as i32);
if r >= 0 {
recvbuffer.set_len(r as usize);
Ok(recvbuffer)
} else {
return kisserr!(KissErrKind::Error, "recv {}", r);
}
}
}
fn finish(&mut self) {
self.release();
}
}
impl BcosNativeTlsClient {
pub fn default(config: &ChannelConfig) -> BcosNativeTlsClient {
BcosNativeTlsClient {
ssocklib: None,
config: config.clone(),
bufferqueue: BufferQueue::new(),
is_valid: false,
is_connect: false,
channelpackpool: Vec::new(),
}
}
pub fn build(&mut self) -> Result<bool, KissError> {
let res = BcosNativeTlsClient::openlib();
let nativelib = match res {
Ok(lib) => lib,
Err(e) => {
return Err(e);
}
};
unsafe {
let func_create: Symbol<FN_SSOCK_CREATE> = (&nativelib).get(b"ssock_create").unwrap();
let pssock_ptr = func_create();
let lib = SSockNativeLib {
pssock: pssock_ptr,
nativelib: nativelib,
};
self.ssocklib = Option::from(lib);
self.set_echo_mode(self.config.nativelib_echo_mode as i32);
self.init()?;
self.connect()?;
self.is_valid = true;
self.is_connect = true;
Ok(self.is_valid)
}
}
pub fn locate_lib_path() -> String {
let mut exepath = env::current_exe().unwrap();
exepath.pop();
let mut libname: String = "native_tassl_sock_wrap".to_string();
if is_windows() {
libname = libname + ".dll";
} else {
libname = format!("lib{}.so",libname);
}
let pathstr = libname;
return pathstr.to_string();
}
pub fn openlib() -> Result<Library, KissError> {
unsafe {
let lib_fullpath = BcosNativeTlsClient::locate_lib_path();
let res = Library::new(lib_fullpath.as_str());
match res {
Ok(lib) => {
return Ok(lib);
}
Err(e) => {
return kisserr!(
KissErrKind::Error,
"load lib error [{}],{:?}",
lib_fullpath,
e
);
}
}
}
}
pub fn create(&self) {
unsafe {
let func_create: Symbol<FN_SSOCK_CREATE> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_create")
.unwrap();
}
}
pub fn release(&mut self) {
if !self.is_valid {
printlnex!("bcostls client is no valid");
return;
};
unsafe {
let func_release: Symbol<FN_SSOCK_RELEASE> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_release")
.unwrap();
func_release(self.ssocklib.as_ref().unwrap().pssock);
self.ssocklib = Option::None;
self.is_connect = false;
self.is_valid = false;
printlnex!("bcostls client is released!");
}
}
pub fn set_echo_mode(&self, mode: i32) {
unsafe {
let func_set: Symbol<FN_SSOCK_SET_ECHO_MODE> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_set_echo_mode")
.unwrap();
func_set(self.ssocklib.as_ref().unwrap().pssock, mode);
}
}
pub fn init(&self) -> Result<i32, KissError> {
unsafe {
let func_init: Symbol<FN_SSOCK_INIT> = self
.ssocklib
.as_ref()
.unwrap()
.nativelib
.get(b"ssock_init")
.unwrap();
let r;
match self.config.tlskind {
BcosCryptoKind::ECDSA => {
r = func_init(
self.ssocklib.as_ref().unwrap().pssock,
rzero(&self.config.cacert).as_ptr(),
rzero(&self.config.sdkcert).as_ptr(),
rzero(&self.config.sdkkey).as_ptr(),
rzero(&"".to_string()).as_ptr(),
rzero(&"".to_string()).as_ptr(),
);
}
BcosCryptoKind::GM => {
r = func_init(
self.ssocklib.as_ref().unwrap().pssock,
rzero(&self.config.gmcacert).as_ptr(),
rzero(&self.config.gmsdkcert).as_ptr(),
rzero(&self.config.gmsdkkey).as_ptr(),
rzero(&self.config.gmensdkcert).as_ptr(),
rzero(&self.config.gmensdkkey).as_ptr(),
);
}
}
if r < 0 {
return kisserr!(KissErrKind::ENetwork, "init tls client error {}", r);
}
Ok(r)
}
}
}