Last active
May 7, 2020 03:21
-
-
Save DenWav/cac8c1cc110b1110a373d2389d798c73 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[no_mangle] | |
#[allow(non_snake_case)] | |
pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_receiveMessage( | |
env: JNIEnv, | |
_: JClass, | |
client_desc: jint, | |
) -> jobject { | |
let (message_type, message_length) = match read_meta(&env, client_desc) { | |
Ok((l, r)) => (l, r), | |
Err(_) => return jnull!(), | |
}; | |
const MESSAGE_SIZE: usize = 1000; | |
let mut message_buffer: [u8; MESSAGE_SIZE] = [0; MESSAGE_SIZE]; | |
let mut output_buffer = Vec::<u8>::new(); | |
let mut total_received: usize = 0; | |
while total_received < message_length { | |
let rcv_amount = recv(client_desc, &mut message_buffer, MsgFlags::empty()); | |
let rcv_amount = handle_managed_syscall!(obj, env, rcv_amount); | |
total_received += rcv_amount; | |
output_buffer.copy_from_slice(&message_buffer[..rcv_amount]); | |
} | |
let message_string = String::from_utf8(output_buffer); | |
let message_string = match message_string { | |
Ok(s) => s, | |
Err(e) => { | |
let err_str = format!("Message from paperd client not valid UTF-8: {}", e); | |
throw(&env, err_str.as_str()); | |
return jnull!(); | |
} | |
}; | |
let result_string = env.new_string(message_string); | |
let result_string = match result_string { | |
Ok(s) => s, | |
Err(e) => return jnull!(), | |
}; | |
let result_obj = env.new_object( | |
buffer_class!(), | |
"(JLjava/lang/String;)V", | |
&[ | |
JValue::Long(message_type), | |
JValue::Object(JObject::from(result_string)), | |
], | |
); | |
return match result_obj { | |
Ok(o) => o.into_inner(), | |
Err(e) => jnull!(), | |
}; | |
} | |
fn read_meta(env: &JNIEnv, desc: RawFd) -> Result<(i64, usize), ()> { | |
// meta_buffer will contain: | |
// * message_type (first 8 bytes) | |
// * message_length (last 8 bytes) | |
// 8 bytes for each is overkill by an enormous margin, but 16 bytes is cheap and easy to do so | |
// there's not really much downside | |
// | |
// Both numbers are big endian | |
const META_SIZE: usize = 8; | |
let mut meta_buffer: [u8; META_SIZE] = [0; META_SIZE]; | |
let message_type = match read_i64(env, desc, &mut meta_buffer) { | |
Ok(v) => v, | |
_ => return Err(()), | |
}; | |
let message_size = match read_i64(env, desc, &mut meta_buffer) { | |
Ok(v) => v as usize, | |
_ => return Err(()), | |
}; | |
return Ok((message_type, message_size)); | |
} | |
fn read_i64(env: &JNIEnv, desc: RawFd, buffer: &mut [u8; 8]) -> Result<i64, ()> { | |
let rcv_amount = recv(desc, buffer, MsgFlags::MSG_WAITALL); | |
let rcv_amount = handle_managed_syscall!(err(()), env, rcv_amount); | |
if rcv_amount != 8 { | |
throw( | |
env, | |
"Failed to read data from client, but no error was returned", | |
); | |
return Err(()); | |
} | |
let parsed_val: i64 = i64::from_be_bytes(*buffer); | |
return Ok(parsed_val); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment