├── .gitignore
├── .travis.yml
├── COPYING.lesser
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── build.rs
├── header.txt
├── paperd-jni
├── Cargo.lock
├── Cargo.toml
├── header.h
└── src
│ ├── lib.rs
│ ├── macros.rs
│ └── util.rs
├── paperd-lib
├── Cargo.lock
├── Cargo.toml
└── src
│ └── lib.rs
├── protocol.md
├── readme.md
├── release
├── .gitignore
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── paperd_install.sh
├── readme.md
├── settings.gradle.kts
└── targets
│ ├── .dockerignore
│ ├── build_release.sh
│ ├── centos
│ ├── centos.Dockerfile
│ └── versions.txt
│ ├── debian
│ ├── debian.Dockerfile
│ └── versions.txt
│ ├── fedora
│ ├── fedora.Dockerfile
│ └── versions.txt
│ └── ubuntu
│ ├── ubuntu.Dockerfile
│ └── versions.txt
├── src
├── cmd.rs
├── console
│ ├── ansi.rs
│ └── mod.rs
├── daemon.rs
├── log.rs
├── main.rs
├── messages.rs
├── messaging.rs
├── protocol.rs
├── restart.rs
├── runner.rs
├── send.rs
├── status.rs
├── stop.rs
├── timings.rs
└── util.rs
└── usage.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /paperd.tar.xz
2 | /paperd
3 |
4 | .idea/
5 |
6 | /target
7 | /paperd-lib/target
8 | /paperd-jni/target
9 | **/*.rs.bk
10 |
11 | ### Linux ###
12 | *~
13 |
14 | # temporary files which can be created if a process still has a handle open of a deleted file
15 | .fuse_hidden*
16 |
17 | # KDE directory preferences
18 | .directory
19 |
20 | # Linux trash folder which might appear on any partition or disk
21 | .Trash-*
22 |
23 | # .nfs files are created when an open file is removed but is still being accessed
24 | .nfs*
25 |
26 | ### macOS ###
27 | # General
28 | .DS_Store
29 | .AppleDouble
30 | .LSOverride
31 |
32 | # Icon must end with two \r
33 | Icon
34 |
35 | # Thumbnails
36 | ._*
37 |
38 | # Files that might appear in the root of a volume
39 | .DocumentRevisions-V100
40 | .fseventsd
41 | .Spotlight-V100
42 | .TemporaryItems
43 | .Trashes
44 | .VolumeIcon.icns
45 | .com.apple.timemachine.donotpresent
46 |
47 | # Directories potentially created on remote AFP share
48 | .AppleDB
49 | .AppleDesktop
50 | Network Trash Folder
51 | Temporary Items
52 | .apdisk
53 |
54 | ### Windows ###
55 | # Windows thumbnail cache files
56 | Thumbs.db
57 | ehthumbs.db
58 | ehthumbs_vista.db
59 |
60 | # Dump file
61 | *.stackdump
62 |
63 | # Folder config file
64 | [Dd]esktop.ini
65 |
66 | # Recycle Bin used on file shares
67 | $RECYCLE.BIN/
68 |
69 | # Windows Installer files
70 | *.cab
71 | *.msi
72 | *.msix
73 | *.msm
74 | *.msp
75 |
76 | # Windows shortcuts
77 | *.lnk
78 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | rust:
3 | - stable
4 | - beta
5 | - nightly
6 | env:
7 | - CMD="cargo build"
8 | - CMD="cargo build --features console"
9 | matrix:
10 | allow_failures:
11 | - rust: beta
12 | - rust: nightly
13 | fast_finish: true
14 | cache: cargo
15 | script:
16 | - $CMD
17 | addons:
18 | apt:
19 | packages:
20 | - libncurses5
21 | - libncursesw5
22 | - libncurses5-dev
23 | - libncursesw5-dev
24 | update: true
25 |
--------------------------------------------------------------------------------
/COPYING.lesser:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "paperd"
3 | version = "1.1.0-snapshot"
4 | authors = ["Kyle Wood "]
5 | edition = "2018"
6 | license = "LGPL-3.0-only"
7 |
8 | [features]
9 | console = ["ncurses"]
10 |
11 | [profile.release]
12 | opt-level = 'z' # Optimize for size.
13 | lto = true
14 | codegen-units = 1
15 |
16 | [dependencies]
17 | clap = "2.33.1"
18 | crossbeam-channel = "0.4.2"
19 | ncurses = { version = "5.99.0", optional = true, features = ['wide'] }
20 | nix = "0.17.0"
21 | serde = { version = "1.0.110", features = ["derive"] }
22 | serde_json = "1.0.53"
23 | shellexpand = "2.0.0"
24 | signal-hook = "0.1.15"
25 | sys-info = "0.6.1"
26 | zip = "0.5.5"
27 | paperd-lib = { path = "./paperd-lib/" }
28 |
29 | [build-dependencies]
30 | flate2 = "1.0.14"
31 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | // This file is part of paperd, the PaperMC server daemon
2 | // Copyright (C) 2019 Kyle Wood (DemonWav)
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, version 3 only.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU Lesser General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU Lesser General Public License
14 | // along with this program. If not, see .
15 |
16 | use flate2::write::GzEncoder;
17 | use flate2::Compression;
18 | use std::env;
19 | use std::fs::OpenOptions;
20 | use std::io::copy;
21 | use std::io::{BufReader, Read};
22 | use std::process::{Command, Stdio};
23 |
24 | fn main() {
25 | let out_dir = env::var("OUT_DIR").unwrap();
26 | let cargo_loc = env::var("CARGO").unwrap();
27 | let profile = env::var("PROFILE").unwrap();
28 | let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
29 | let num_jobs = env::var("NUM_JOBS").unwrap();
30 |
31 | let is_release = profile == "release";
32 | let is_mac = target_os == "macos";
33 | let extension = if is_mac { "dylib" } else { "so" };
34 |
35 | build_jni(&cargo_loc, is_release, &out_dir, &num_jobs);
36 |
37 | let lib_file_name = if is_release {
38 | "release/libpaperd_jni"
39 | } else {
40 | "debug/libpaperd_jni"
41 | };
42 | let lib_file = format!("{}/{}.{}", out_dir, lib_file_name, extension);
43 |
44 | if is_release {
45 | strip(lib_file.as_str(), is_mac);
46 | }
47 | compress(lib_file.as_str());
48 |
49 | println!("cargo:rustc-env=PAPERD_JNI_LIB={}.gz", lib_file);
50 | }
51 |
52 | fn build_jni(cargo_loc: &str, is_release: bool, out_dir: &str, num_jobs: &str) {
53 | let mut command = Command::new(cargo_loc);
54 | let mut command =
55 | command
56 | .current_dir("paperd-jni")
57 | .args(&["build", "-j", num_jobs, "--target-dir", out_dir]);
58 |
59 | if is_release {
60 | command.arg("--release");
61 | }
62 |
63 | execute(&mut command);
64 | }
65 |
66 | fn strip(lib_file: &str, is_mac: bool) {
67 | if is_mac {
68 | let mut command = Command::new("strip");
69 | let mut command = command.args(&["-x", lib_file]);
70 | execute(&mut command);
71 | } else {
72 | let nm_process = Command::new("nm")
73 | .args(&["--extern-only", lib_file])
74 | .stdout(Stdio::piped())
75 | .spawn()
76 | .unwrap();
77 |
78 | let mut output = String::new();
79 | nm_process
80 | .stdout
81 | .unwrap()
82 | .read_to_string(&mut output)
83 | .unwrap();
84 |
85 | let symbols: Vec<&str> = output
86 | .lines()
87 | .filter_map(|line| {
88 | let parts: Vec<&str> = line.split_whitespace().collect();
89 | if parts.len() < 3 {
90 | return None;
91 | }
92 | let part = parts[2];
93 | return if part.starts_with("Java_com_destroystokyo_paper") {
94 | Some(part)
95 | } else {
96 | None
97 | };
98 | })
99 | .collect();
100 |
101 | let mut command = Command::new("strip");
102 | for symbol in symbols {
103 | command.args(&["-K", symbol]);
104 | }
105 | command.arg(lib_file);
106 |
107 | execute(&mut command);
108 | }
109 | }
110 |
111 | fn compress(lib_file: &str) {
112 | let output_file = format!("{}.gz", lib_file);
113 |
114 | let file = OpenOptions::new()
115 | .write(true)
116 | .create(true)
117 | .truncate(true)
118 | .open(output_file)
119 | .unwrap();
120 |
121 | let mut encoder = GzEncoder::new(file, Compression::best());
122 |
123 | let source_file = OpenOptions::new().read(true).open(lib_file).unwrap();
124 | let mut input = BufReader::new(source_file);
125 |
126 | copy(&mut input, &mut encoder).unwrap();
127 | }
128 |
129 | fn execute(cmd: &mut Command) {
130 | if cmd.spawn().unwrap().wait().unwrap().code().unwrap() != 0 {
131 | panic!("Failed to execute command");
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/header.txt:
--------------------------------------------------------------------------------
1 | This file is part of paperd, the PaperMC server daemon
2 | Copyright (C) 2019 Kyle Wood (DemonWav)
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU Lesser General Public License as published by
6 | the Free Software Foundation, version 3 only.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU Lesser General Public License for more details.
12 |
13 | You should have received a copy of the GNU Lesser General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/paperd-jni/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "ascii"
5 | version = "0.9.2"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 |
8 | [[package]]
9 | name = "backtrace"
10 | version = "0.3.32"
11 | source = "registry+https://github.com/rust-lang/crates.io-index"
12 | dependencies = [
13 | "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
14 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
15 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
16 | "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
17 | ]
18 |
19 | [[package]]
20 | name = "backtrace-sys"
21 | version = "0.1.30"
22 | source = "registry+https://github.com/rust-lang/crates.io-index"
23 | dependencies = [
24 | "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
25 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
26 | ]
27 |
28 | [[package]]
29 | name = "bitflags"
30 | version = "1.1.0"
31 | source = "registry+https://github.com/rust-lang/crates.io-index"
32 |
33 | [[package]]
34 | name = "byteorder"
35 | version = "1.3.2"
36 | source = "registry+https://github.com/rust-lang/crates.io-index"
37 |
38 | [[package]]
39 | name = "cc"
40 | version = "1.0.37"
41 | source = "registry+https://github.com/rust-lang/crates.io-index"
42 |
43 | [[package]]
44 | name = "cesu8"
45 | version = "1.1.0"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 |
48 | [[package]]
49 | name = "cfg-if"
50 | version = "0.1.9"
51 | source = "registry+https://github.com/rust-lang/crates.io-index"
52 |
53 | [[package]]
54 | name = "combine"
55 | version = "3.8.1"
56 | source = "registry+https://github.com/rust-lang/crates.io-index"
57 | dependencies = [
58 | "ascii 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
59 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
60 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
61 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
62 | "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
63 | ]
64 |
65 | [[package]]
66 | name = "either"
67 | version = "1.5.2"
68 | source = "registry+https://github.com/rust-lang/crates.io-index"
69 |
70 | [[package]]
71 | name = "error-chain"
72 | version = "0.12.1"
73 | source = "registry+https://github.com/rust-lang/crates.io-index"
74 | dependencies = [
75 | "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
76 | "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
77 | ]
78 |
79 | [[package]]
80 | name = "jni"
81 | version = "0.16.0"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | dependencies = [
84 | "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
85 | "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
86 | "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
87 | "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
88 | "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
89 | "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
90 | ]
91 |
92 | [[package]]
93 | name = "jni-sys"
94 | version = "0.3.0"
95 | source = "registry+https://github.com/rust-lang/crates.io-index"
96 |
97 | [[package]]
98 | name = "libc"
99 | version = "0.2.60"
100 | source = "registry+https://github.com/rust-lang/crates.io-index"
101 |
102 | [[package]]
103 | name = "log"
104 | version = "0.4.7"
105 | source = "registry+https://github.com/rust-lang/crates.io-index"
106 | dependencies = [
107 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
108 | ]
109 |
110 | [[package]]
111 | name = "memchr"
112 | version = "2.2.1"
113 | source = "registry+https://github.com/rust-lang/crates.io-index"
114 |
115 | [[package]]
116 | name = "nix"
117 | version = "0.17.0"
118 | source = "registry+https://github.com/rust-lang/crates.io-index"
119 | dependencies = [
120 | "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
121 | "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
122 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
123 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
124 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
125 | ]
126 |
127 | [[package]]
128 | name = "paperd-jni"
129 | version = "1.1.0-snapshot"
130 | dependencies = [
131 | "jni 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
132 | "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
133 | "paperd-lib 1.1.0-snapshot",
134 | ]
135 |
136 | [[package]]
137 | name = "paperd-lib"
138 | version = "1.1.0-snapshot"
139 | dependencies = [
140 | "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
141 | ]
142 |
143 | [[package]]
144 | name = "rustc-demangle"
145 | version = "0.1.15"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 |
148 | [[package]]
149 | name = "same-file"
150 | version = "1.0.4"
151 | source = "registry+https://github.com/rust-lang/crates.io-index"
152 | dependencies = [
153 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
154 | ]
155 |
156 | [[package]]
157 | name = "unreachable"
158 | version = "1.0.0"
159 | source = "registry+https://github.com/rust-lang/crates.io-index"
160 | dependencies = [
161 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
162 | ]
163 |
164 | [[package]]
165 | name = "version_check"
166 | version = "0.1.5"
167 | source = "registry+https://github.com/rust-lang/crates.io-index"
168 |
169 | [[package]]
170 | name = "void"
171 | version = "1.0.2"
172 | source = "registry+https://github.com/rust-lang/crates.io-index"
173 |
174 | [[package]]
175 | name = "walkdir"
176 | version = "2.2.8"
177 | source = "registry+https://github.com/rust-lang/crates.io-index"
178 | dependencies = [
179 | "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
180 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
181 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
182 | ]
183 |
184 | [[package]]
185 | name = "winapi"
186 | version = "0.3.7"
187 | source = "registry+https://github.com/rust-lang/crates.io-index"
188 | dependencies = [
189 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
190 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
191 | ]
192 |
193 | [[package]]
194 | name = "winapi-i686-pc-windows-gnu"
195 | version = "0.4.0"
196 | source = "registry+https://github.com/rust-lang/crates.io-index"
197 |
198 | [[package]]
199 | name = "winapi-util"
200 | version = "0.1.2"
201 | source = "registry+https://github.com/rust-lang/crates.io-index"
202 | dependencies = [
203 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
204 | ]
205 |
206 | [[package]]
207 | name = "winapi-x86_64-pc-windows-gnu"
208 | version = "0.4.0"
209 | source = "registry+https://github.com/rust-lang/crates.io-index"
210 |
211 | [metadata]
212 | "checksum ascii 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "91e320562a8fa3286a481b7189f89578ace6b20df99e123c87f2f509c957c5d6"
213 | "checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5"
214 | "checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61"
215 | "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
216 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
217 | "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
218 | "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
219 | "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
220 | "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
221 | "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
222 | "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
223 | "checksum jni 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22bbdc25b49340bc4fc3d9c96dd84d878c4beeca35e3651efa53db51a68d7d4d"
224 | "checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
225 | "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
226 | "checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3"
227 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
228 | "checksum nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
229 | "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
230 | "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
231 | "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
232 | "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
233 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
234 | "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45"
235 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
236 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
237 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
238 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
239 |
--------------------------------------------------------------------------------
/paperd-jni/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "paperd-jni"
3 | version = "1.1.0-snapshot"
4 | authors = ["Kyle Wood "]
5 | edition = "2018"
6 |
7 | [lib]
8 | crate_type = ["cdylib"]
9 |
10 | [profile.release]
11 | opt-level = 'z' # Optimize for size.
12 | lto = true
13 | codegen-units = 1
14 |
15 | [dependencies]
16 | jni = "0.16.0"
17 | nix = "0.17.0"
18 | paperd-lib = { path = "../paperd-lib/" }
19 |
--------------------------------------------------------------------------------
/paperd-jni/header.h:
--------------------------------------------------------------------------------
1 | /* DO NOT EDIT THIS FILE - it is machine generated */
2 | #include
3 | /* Header for class com_destroystokyo_paper_daemon_PaperDaemonJni */
4 |
5 | #ifndef _Included_com_destroystokyo_paper_daemon_PaperDaemonJni
6 | #define _Included_com_destroystokyo_paper_daemon_PaperDaemonJni
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 | /*
11 | * Class: com_destroystokyo_paper_daemon_PaperDaemonJni
12 | * Method: createQueue
13 | * Signature: (Ljava/nio/file/Path;)I
14 | */
15 | JNIEXPORT jint JNICALL Java_com_destroystokyo_paper_daemon_PaperDaemonJni_createSocket
16 | (JNIEnv *, jclass, jobject);
17 |
18 | /*
19 | * Class: com_destroystokyo_paper_daemon_PaperDaemonJni
20 | * Method: acceptConnection
21 | * Signature: (I)Ljava/util/OptionalInt;
22 | */
23 | JNIEXPORT jint JNICALL Java_com_destroystokyo_paper_daemon_PaperDaemonJni_acceptConnection
24 | (JNIEnv *, jclass, jint);
25 |
26 | /*
27 | * Class: com_destroystokyo_paper_daemon_PaperDaemonJni
28 | * Method: receiveMessage
29 | * Signature: (I)Lcom/destroystokyo/paper/daemon/PaperDaemonMessageBuffer;
30 | */
31 | JNIEXPORT jobject JNICALL Java_com_destroystokyo_paper_daemon_PaperDaemonJni_receiveMessage
32 | (JNIEnv *, jclass, jint);
33 |
34 | /*
35 | * Class: com_destroystokyo_paper_daemon_PaperDaemonJni
36 | * Method: sendMessage
37 | * Signature: (ILcom/destroystokyo/paper/daemon/PaperDaemonMessageBuffer;)V
38 | */
39 | JNIEXPORT void JNICALL Java_com_destroystokyo_paper_daemon_PaperDaemonJni_sendMessage
40 | (JNIEnv *, jclass, jint, jobject);
41 |
42 | /*
43 | * Class: com_destroystokyo_paper_daemon_PaperDaemonJni
44 | * Method: closeSocket
45 | * Signature: (I)V
46 | */
47 | JNIEXPORT void JNICALL Java_com_destroystokyo_paper_daemon_PaperDaemonJni_closeSocket
48 | (JNIEnv *, jclass, jint);
49 |
50 | #ifdef __cplusplus
51 | }
52 | #endif
53 | #endif
54 |
--------------------------------------------------------------------------------
/paperd-jni/src/lib.rs:
--------------------------------------------------------------------------------
1 | // This file is part of paperd, the PaperMC server daemon
2 | // Copyright (C) 2019 Kyle Wood (DemonWav)
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, version 3 only.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU Lesser General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU Lesser General Public License
14 | // along with this program. If not, see .
15 |
16 | extern crate alloc;
17 | extern crate jni;
18 | extern crate nix;
19 | extern crate paperd_lib;
20 |
21 | use jni::objects::{JClass, JObject, JString, JValue};
22 | use jni::sys::{jint, jobject};
23 | use jni::JNIEnv;
24 | use nix::errno::Errno;
25 | use paperd_lib::{accept_connection, bind_socket, Error};
26 |
27 | use paperd_lib::{
28 | close_socket, create_socket, receive_message, send_message, Message, MessageHeader,
29 | };
30 |
31 | use crate::util::{
32 | get_path_string, throw, throw_socket_closed, throw_timeout, throw_with_cause, JAVA_STRING_TYPE,
33 | NPE_CLASS,
34 | };
35 |
36 | #[macro_use]
37 | mod macros;
38 | mod util;
39 |
40 | const BUFFER_CLASS: &str = "com/destroystokyo/paper/daemon/PaperDaemonMessageBuffer";
41 | const BUFFER_CONST: &str = "(JLjava/lang/String;)V";
42 |
43 | #[no_mangle]
44 | #[allow(non_snake_case)]
45 | pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_createSocket(
46 | env: JNIEnv,
47 | _: JClass,
48 | sock_file: JObject,
49 | ) -> jint {
50 | let sock_file_path = match get_path_string(&env, sock_file) {
51 | Ok(str) => str,
52 | _ => {
53 | const MESSAGE: &'static str = "Failed to get absolute path to PID file";
54 | match env.exception_occurred() {
55 | Ok(thrown) => {
56 | if thrown.is_null() {
57 | throw(&env, MESSAGE);
58 | }
59 | let _ = env.exception_clear();
60 | throw_with_cause(&env, MESSAGE, &thrown);
61 | }
62 | Err(_) => {
63 | throw(&env, MESSAGE);
64 | }
65 | }
66 | return -1;
67 | }
68 | };
69 |
70 | let sock = handle_syscall!(env, create_socket(), -1);
71 | handle_syscall!(env, bind_socket(sock, sock_file_path.as_str()), -1);
72 |
73 | return sock;
74 | }
75 |
76 | #[no_mangle]
77 | #[allow(non_snake_case)]
78 | pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_acceptConnection(
79 | env: JNIEnv,
80 | _: JClass,
81 | sock: jint,
82 | ) -> jint {
83 | let client_sock = handle_syscall!(env, accept_connection(sock), 0);
84 |
85 | return if let Some(value) = client_sock {
86 | value
87 | } else {
88 | throw_timeout(&env);
89 | 0
90 | };
91 | }
92 |
93 | #[no_mangle]
94 | #[allow(non_snake_case)]
95 | pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_receiveMessage(
96 | env: JNIEnv,
97 | _: JClass,
98 | client_sock: jint,
99 | ) -> jobject {
100 | let message = match receive_message(client_sock) {
101 | Ok(opt) => match opt {
102 | Some(m) => m,
103 | None => return jnull!(),
104 | },
105 | Err(Error::Nix(nix::Error::Sys(Errno::EAGAIN), _)) => {
106 | // timeout
107 | throw_timeout(&env);
108 | return jnull!();
109 | }
110 | Err(e) => {
111 | let error_msg = format!("Error attempting system call: {}", e);
112 | throw(&env, error_msg.as_str());
113 | return jnull!();
114 | }
115 | };
116 |
117 | let result_string = match env.new_string(message.message_text) {
118 | Ok(s) => s,
119 | Err(_) => return jnull!(),
120 | };
121 |
122 | let result_obj = env.new_object(
123 | BUFFER_CLASS,
124 | BUFFER_CONST,
125 | &[
126 | JValue::Long(message.header.message_type),
127 | JValue::Object(JObject::from(result_string)),
128 | ],
129 | );
130 |
131 | return match result_obj {
132 | Ok(o) => o.into_inner(),
133 | Err(_) => jnull!(),
134 | };
135 | }
136 |
137 | #[no_mangle]
138 | #[allow(non_snake_case)]
139 | pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_sendMessage(
140 | env: JNIEnv,
141 | _: JClass,
142 | client_sock: jint,
143 | message: jobject,
144 | ) {
145 | if message.is_null() {
146 | let _ = env.throw_new(NPE_CLASS, "message must not be null");
147 | return;
148 | }
149 |
150 | let message_type = get_field!(env, message, "messageType", Long);
151 | let message_data = get_field!(env, message, "messageData", Object(JAVA_STRING_TYPE));
152 |
153 | let java_string = env.get_string(JString::from(message_data));
154 | let java_string = match java_string {
155 | Ok(s) => String::from(s),
156 | Err(e) => {
157 | let error_msg = format!("Failed to retrieve string from message: {}", e);
158 | throw(&env, error_msg.as_str());
159 | return;
160 | }
161 | };
162 |
163 | let message = Message {
164 | header: MessageHeader {
165 | message_type,
166 | message_length: java_string.len() as i64,
167 | },
168 | message_text: java_string,
169 | };
170 |
171 | match send_message(client_sock, &message) {
172 | Err(Error::Nix(nix::Error::Sys(Errno::EPIPE), _)) => {
173 | throw_socket_closed(&env);
174 | }
175 | Err(e) => {
176 | let error_msg = format!("Failed to send message to {}: {}", client_sock, e);
177 | throw(&env, error_msg.as_str());
178 | }
179 | _ => {}
180 | }
181 | }
182 |
183 | #[no_mangle]
184 | #[allow(non_snake_case)]
185 | pub extern "system" fn Java_com_destroystokyo_paper_daemon_PaperDaemonJni_closeSocket(
186 | env: JNIEnv,
187 | _: JClass,
188 | sock: jint,
189 | ) {
190 | if let Err(e) = close_socket(sock) {
191 | let error_msg = format!("Error while closing socket {}: {}", sock, e);
192 | throw(&env, error_msg.as_str());
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/paperd-jni/src/macros.rs:
--------------------------------------------------------------------------------
1 | // This file is part of paperd, the PaperMC server daemon
2 | // Copyright (C) 2019 Kyle Wood (DemonWav)
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, version 3 only.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU Lesser General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU Lesser General Public License
14 | // along with this program. If not, see .
15 |
16 | macro_rules! jnull {
17 | () => {
18 | jni::objects::JObject::null().into_inner()
19 | };
20 | }
21 |
22 | macro_rules! get_field {
23 | ($env:ident, $obj:ident, $name:expr, Object($ty:expr)) => {
24 | get_field!($env, $obj, $name, (jni::objects::JValue::Object, $ty))
25 | };
26 | ($env:ident, $obj:ident, $name:expr, Byte) => {
27 | get_field!($env, $obj, $name, (jni::objects::JValue::Byte, "B"))
28 | };
29 | ($env:ident, $obj:ident, $name:expr, Char) => {
30 | get_field!($env, $obj, $name, (jni::objects::JValue::Char, "C"))
31 | };
32 | ($env:ident, $obj:ident, $name:expr, Short) => {
33 | get_field!($env, $obj, $name, (jni::objects::JValue::Short, "S"))
34 | };
35 | ($env:ident, $obj:ident, $name:expr, Int) => {
36 | get_field!($env, $obj, $name, (jni::objects::JValue::Int, "I"))
37 | };
38 | ($env:ident, $obj:ident, $name:expr, Long) => {
39 | get_field!($env, $obj, $name, (jni::objects::JValue::Long, "J"))
40 | };
41 | ($env:ident, $obj:ident, $name:expr, Bool) => {
42 | get_field!($env, $obj, $name, (jni::objects::JValue::Bool, "Z"))
43 | };
44 | ($env:ident, $obj:ident, $name:expr, Float) => {
45 | get_field!($env, $obj, $name, (jni::objects::JValue::Float, "F"))
46 | };
47 | ($env:ident, $obj:ident, $name:expr, Double) => {
48 | get_field!($env, $obj, $name, (jni::objects::JValue::Double, "D"))
49 | };
50 | ($env:ident, $obj:ident, $name:expr, Void) => {
51 | get_field!($env, $obj, $name, (jni::objects::JValue::Void, "V"))
52 | };
53 | ($env:ident, $obj:ident, $name:expr, ($ret:path, $ty:expr)) => {
54 | match $env.get_field($obj, $name, $ty) {
55 | Ok($ret(t)) => t,
56 | _ => {
57 | let class_name = crate::util::get_class_name(&$env, $obj);
58 | let error_msg = format!(stringify!(Failed to get $name from {}), class_name.as_str());
59 | throw(&$env, error_msg.as_str());
60 | return;
61 | }
62 | };
63 | };
64 | }
65 |
66 | macro_rules! handle_syscall {
67 | ($env:ident, $call:expr, $return:expr) => {
68 | match $call {
69 | Ok(v) => v,
70 | Err(e) => {
71 | let error_msg = format!("Error attempting system call: {}", e);
72 | throw(&$env, error_msg.as_str());
73 | return $return;
74 | }
75 | }
76 | };
77 | }
78 |
--------------------------------------------------------------------------------
/paperd-jni/src/util.rs:
--------------------------------------------------------------------------------
1 | // This file is part of paperd, the PaperMC server daemon
2 | // Copyright (C) 2019 Kyle Wood (DemonWav)
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, version 3 only.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU Lesser General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU Lesser General Public License
14 | // along with this program. If not, see .
15 |
16 | use jni::objects::JValue::Object;
17 | use jni::objects::{JObject, JString, JThrowable, JValue};
18 | use jni::sys::jobject;
19 | use jni::JNIEnv;
20 | use std::string::String;
21 |
22 | pub const JAVA_STRING_TYPE: &'static str = "Ljava/lang/String;";
23 | pub const NPE_CLASS: &'static str = "java/lang/NullPointerException";
24 |
25 | pub fn get_path_string(env: &JNIEnv, path: JObject) -> Result {
26 | let abs_path = match env.call_method(path, "toAbsolutePath", "()Ljava/nio/file/Path;", &[]) {
27 | Ok(Object(obj)) => obj,
28 | _ => return Err(()),
29 | };
30 | if env.exception_check().unwrap_or(false) {
31 | return Err(());
32 | }
33 |
34 | let java_string = match env.call_method(abs_path, "toString", "()Ljava/lang/String;", &[]) {
35 | Ok(Object(obj)) => obj,
36 | _ => return Err(()),
37 | };
38 | if env.exception_check().unwrap_or(false) {
39 | return Err(());
40 | }
41 |
42 | let text = match env.get_string(java_string.into()) {
43 | Ok(str) => str,
44 | _ => return Err(()),
45 | };
46 | return Ok(text.into());
47 | }
48 |
49 | const NATIVE_EXCEPTION_CLASS: &'static str = "com/destroystokyo/paper/daemon/NativeErrorException";
50 | const NATIVE_TIMEOUT_EXCEPTION_CLASS: &'static str =
51 | "com/destroystokyo/paper/daemon/NativeTimeoutException";
52 | const NATIVE_SOCKET_CLOSED_CLASS: &'static str =
53 | "com/destroystokyo/paper/daemon/NativeSocketClosedException";
54 |
55 | pub fn throw(env: &JNIEnv, message: &str) {
56 | let _ = env.throw_new(NATIVE_EXCEPTION_CLASS, message);
57 | }
58 |
59 | pub fn throw_timeout(env: &JNIEnv) {
60 | throw_blank(env, NATIVE_TIMEOUT_EXCEPTION_CLASS);
61 | }
62 |
63 | pub fn throw_socket_closed(env: &JNIEnv) {
64 | throw_blank(env, NATIVE_SOCKET_CLOSED_CLASS);
65 | }
66 |
67 | fn throw_blank(env: &JNIEnv, class: &str) {
68 | let obj = env.new_object(class, "()V", &[]);
69 | if obj.is_ok() {
70 | let _ = env.throw(JThrowable::from(obj.unwrap()));
71 | }
72 | }
73 |
74 | pub fn throw_with_cause(env: &JNIEnv, message: &str, cause: &JThrowable) {
75 | let java_string = match env.new_string(message) {
76 | Ok(string) => string,
77 | Err(_) => JString::from(jnull!()),
78 | };
79 |
80 | let ex_obj = match env.new_object(
81 | NATIVE_EXCEPTION_CLASS,
82 | "(Ljava/lang/String;Ljava/lang/Throwable;)V",
83 | &[
84 | JValue::Object(JObject::from(java_string)),
85 | JValue::Object(JObject::from(*cause)),
86 | ],
87 | ) {
88 | Ok(obj) => obj,
89 | Err(_) => {
90 | // Just attempt to throw an exception with a cause
91 | throw(env, message);
92 | return;
93 | }
94 | };
95 |
96 | let _ = env.throw(JThrowable::from(ex_obj));
97 | }
98 |
99 | pub fn get_class_name(env: &JNIEnv, obj: jobject) -> String {
100 | return env
101 | .get_object_class(obj)
102 | .and_then(|class| env.call_method(class, "getName", "()Ljava/lang/String;", &[]))
103 | .and_then(|class_name| class_name.l())
104 | .and_then(|class_name| env.get_string(class_name.into()))
105 | .map(|str| String::from(str))
106 | .unwrap_or(String::from(""));
107 | }
108 |
--------------------------------------------------------------------------------
/paperd-lib/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "bitflags"
5 | version = "1.2.1"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 |
8 | [[package]]
9 | name = "cc"
10 | version = "1.0.52"
11 | source = "registry+https://github.com/rust-lang/crates.io-index"
12 |
13 | [[package]]
14 | name = "cfg-if"
15 | version = "0.1.10"
16 | source = "registry+https://github.com/rust-lang/crates.io-index"
17 |
18 | [[package]]
19 | name = "libc"
20 | version = "0.2.69"
21 | source = "registry+https://github.com/rust-lang/crates.io-index"
22 |
23 | [[package]]
24 | name = "nix"
25 | version = "0.17.0"
26 | source = "registry+https://github.com/rust-lang/crates.io-index"
27 | dependencies = [
28 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
29 | "cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
30 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
31 | "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
32 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
33 | ]
34 |
35 | [[package]]
36 | name = "paperd-lib"
37 | version = "1.1.0-snapshot"
38 | dependencies = [
39 | "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
40 | ]
41 |
42 | [[package]]
43 | name = "void"
44 | version = "1.0.2"
45 | source = "registry+https://github.com/rust-lang/crates.io-index"
46 |
47 | [metadata]
48 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
49 | "checksum cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
50 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
51 | "checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
52 | "checksum nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
53 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
54 |
--------------------------------------------------------------------------------
/paperd-lib/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "paperd-lib"
3 | version = "1.1.0-snapshot"
4 | authors = ["Kyle Wood "]
5 | edition = "2018"
6 |
7 | [profile.release]
8 | opt-level = 'z' # Optimize for size.
9 | lto = true
10 | codegen-units = 1
11 |
12 | [dependencies]
13 | nix = "0.17.0"
14 |
--------------------------------------------------------------------------------
/paperd-lib/src/lib.rs:
--------------------------------------------------------------------------------
1 | // This file is part of paperd, the PaperMC server daemon
2 | // Copyright (C) 2019 Kyle Wood (DemonWav)
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, version 3 only.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU Lesser General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU Lesser General Public License
14 | // along with this program. If not, see .
15 |
16 | extern crate nix;
17 |
18 | use nix::errno::Errno;
19 | use nix::sys::socket::sockopt::{ReceiveTimeout, SendTimeout};
20 | use nix::sys::socket::{
21 | accept, bind, connect, listen, recv, send, setsockopt, socket, AddressFamily, MsgFlags,
22 | SockAddr, SockFlag, SockType, UnixAddr,
23 | };
24 | use nix::sys::time::{TimeVal, TimeValLike};
25 | use nix::unistd::{close, unlink};
26 | use nix::NixPath;
27 | use std::cmp::min;
28 | use std::fmt;
29 | use std::fmt::Display;
30 | use std::os::unix::io::RawFd;
31 | use std::string::FromUtf8Error;
32 | use std::time::{Duration, Instant};
33 |
34 | macro_rules! syscall {
35 | ($syscall:ident($( $args:expr ),*)) => {
36 | $syscall($($args,)*).map_err(|e| crate::Error::from(e).for_syscall(stringify!($syscall)))
37 | };
38 | }
39 |
40 | pub struct MessageHeader {
41 | pub message_type: i64,
42 | pub message_length: i64,
43 | }
44 |
45 | pub struct Message {
46 | pub header: MessageHeader,
47 | pub message_text: String,
48 | }
49 |
50 | pub type Socket = RawFd;
51 |
52 | const META_SIZE: usize = 8;
53 | const MESSAGE_SIZE: usize = 1000;
54 | const TIMEOUT_MILLIS: u64 = 500;
55 |
56 | pub fn create_socket() -> Result {
57 | let sock = syscall!(socket(
58 | AddressFamily::Unix,
59 | SockType::Stream,
60 | SockFlag::empty(),
61 | None
62 | ))?;
63 |
64 | let time_val = TimeVal::milliseconds((TIMEOUT_MILLIS / 2) as i64);
65 | syscall!(setsockopt(sock, ReceiveTimeout, &time_val))?;
66 | syscall!(setsockopt(sock, SendTimeout, &time_val))?;
67 |
68 | return Ok(sock);
69 | }
70 |
71 | pub fn close_socket(sock: Socket) -> Result<(), Error> {
72 | return syscall!(close(sock));
73 | }
74 |
75 | pub fn bind_socket(sock: Socket, file_path: &str) -> Result<(), Error> {
76 | match syscall!(unlink(file_path)) {
77 | Ok(()) => Ok(()),
78 | // ENOENT == no such file or directory, we don't care if it doesn't exist
79 | Err(Error::Nix(nix::Error::Sys(Errno::ENOENT), _)) => Ok(()),
80 | Err(e) => Err(e),
81 | }?;
82 |
83 | let addr = UnixAddr::new(file_path)?;
84 | let sock_addr = SockAddr::Unix(addr);
85 |
86 | syscall!(bind(sock, &sock_addr))?;
87 |
88 | syscall!(listen(sock, 128))?;
89 |
90 | return Ok(());
91 | }
92 |
93 | pub fn connect_socket(sock_file: &P) -> Result {
94 | let sock = create_socket()?;
95 |
96 | let addr = UnixAddr::new(sock_file)?;
97 | let socket_addr = SockAddr::Unix(addr);
98 |
99 | loop {
100 | match syscall!(connect(sock, &socket_addr)) {
101 | Ok(_) => break,
102 | Err(Error::Nix(nix::Error::Sys(Errno::EINPROGRESS), _)) => continue,
103 | Err(e) => return Err(e),
104 | }
105 | }
106 |
107 | return Ok(sock);
108 | }
109 |
110 | macro_rules! handle_timeout {
111 | ($res:ident, $timeout:ident, $start:ident, $has_data:expr) => {
112 | match $res {
113 | Ok(amt) => {
114 | $start = std::time::Instant::now();
115 | Ok(amt)
116 | }
117 | Err(Error::Nix(nix::Error::Sys(Errno::EAGAIN), s)) => {
118 | if $start.elapsed() > $timeout {
119 | if ($has_data) {
120 | // If we've received data and we have a timeout, we can't keep listening
121 | Err((Error::Nix(nix::Error::Sys(Errno::UnknownErrno), s)))
122 | } else {
123 | Err((Error::Nix(nix::Error::Sys(Errno::EAGAIN), s)))
124 | }
125 | } else {
126 | continue;
127 | }
128 | }
129 | Err(e) => Err(e),
130 | }
131 | };
132 | }
133 |
134 | pub fn receive_message(sock: Socket) -> Result