Skip to content

Instantly share code, notes, and snippets.

@DenWav
Last active May 7, 2020 03:21
Show Gist options
  • Save DenWav/cac8c1cc110b1110a373d2389d798c73 to your computer and use it in GitHub Desktop.
Save DenWav/cac8c1cc110b1110a373d2389d798c73 to your computer and use it in GitHub Desktop.
#[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