├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── erpc-sys ├── Cargo.toml ├── README.md ├── build.rs └── src │ ├── client.cpp │ ├── common.h │ ├── ffi.cpp │ ├── ffi.rs │ ├── lib.rs │ └── server.cpp ├── examples ├── client.rs ├── client_raw.rs ├── client_test.rs ├── server.rs ├── server_raw.rs └── server_test.rs └── src ├── context.rs ├── lib.rs ├── msgbuffs.rs ├── nexus.rs ├── reqhandle.rs └── rpc.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /.idea/ 13 | /.vscode/ 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erpc-rs" 3 | version = "0.2.0" 4 | authors = ["Frank Zhou <529808348@qq.com>"] 5 | edition = "2018" 6 | keywords = ["erpc", "rpc", "rust"] 7 | repository = "https://github.com/coinrust/erpc-rs" 8 | readme = "README.md" 9 | description = "eRPC library for Rust" 10 | license = "Apache-2.0" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | erpc-sys = { path = "erpc-sys", version = "0.2" } 16 | 17 | [dev-dependencies] 18 | libc = "0.2" 19 | 20 | [workspace] 21 | members = [ 22 | "erpc-sys" 23 | ] 24 | 25 | [[example]] 26 | name = "client" 27 | path = "examples/client.rs" 28 | 29 | [[example]] 30 | name = "server" 31 | path = "examples/server.rs" 32 | 33 | [[example]] 34 | name = "client_raw" 35 | path = "examples/client_raw.rs" 36 | 37 | [[example]] 38 | name = "server_raw" 39 | path = "examples/server_raw.rs" 40 | 41 | [[example]] 42 | name = "client_test" 43 | path = "examples/client_test.rs" 44 | 45 | [[example]] 46 | name = "server_test" 47 | path = "examples/server_test.rs" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # erpc-rs 2 | eRPC library for Rust 3 | 4 | # Dependencies 5 | ``` 6 | sudo apt install libibverbs-dev libnuma-dev libgflags-dev libgtest-dev libboost-dev 7 | ``` 8 | 9 | # Installing rdma-core 10 | ``` 11 | sudo apt install libibverbs-dev libibverbs1 rdma-core ibverbs-utils 12 | # start 13 | sudo rxe_cfg start 14 | Name Link Driver Speed NMTU IPv4_addr RDEV RMTU 15 | eth0 yes hv_netvsc 16 | # add 17 | sudo rxe_cfg add eth0 18 | # status 19 | sudo rxe_cfg status 20 | Name Link Driver Speed NMTU IPv4_addr RDEV RMTU 21 | eth0 yes hv_netvsc rxe0 1024 (3) 22 | ``` 23 | 24 | # Installing junction & turf 25 | ``` 26 | $ git clone https://github.com/preshing/junction.git 27 | $ git clone https://github.com/preshing/turf.git 28 | $ cd junction 29 | $ mkdir build 30 | $ cd build 31 | $ cmake -DCMAKE_INSTALL_PREFIX=~/junction-install -DJUNCTION_WITH_SAMPLES=OFF .. 32 | $ cmake --build . --target install --config RelWithDebInfo 33 | ``` 34 | 35 | # Installing eRPC 36 | ``` 37 | sudo apt-get install libboost-dev libboost-filesystem-dev libboost-thread-dev libboost-program-options-dev libboost-python-dev libboost-dev 38 | 39 | # Installing googletest 40 | sudo apt install libgtest-dev build-essential cmake 41 | cd /usr/src/googletest 42 | sudo cmake . 43 | sudo cmake --build . --target install 44 | 45 | cd ~/ 46 | git clone https://github.com/erpc-io/eRPC.git 47 | cd eRPC/ 48 | cmake . -DPERF=OFF -DTRANSPORT=infiniband -DROCE=on; make -j; 49 | ``` 50 | 51 | # Build & Run 52 | ``` 53 | # use -DERPC_INFINIBAND=true 54 | ERPC_INFINIBAND=true cargo build 55 | 56 | # use -DERPC_RAW=true 57 | ERPC_RAW=true cargo build 58 | 59 | # use -DERPC_DPDK=true 60 | ERPC_DPDK=true cargo build 61 | 62 | # Set up hugepages 63 | sudo bash -c "echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages" 64 | 65 | # Build examples 66 | cargo build --examples 67 | 68 | # Run examples 69 | sudo ./target/debug/examples/server 70 | sudo ./target/debug/examples/client 71 | ``` 72 | 73 | # Server 74 | ```rust,editable 75 | use erpc_rs::context::AppContext; 76 | use erpc_rs::nexus::Nexus; 77 | use erpc_rs::reqhandle::ReqHandle; 78 | use erpc_rs::rpc::Rpc; 79 | use erpc_sys::ffi; 80 | use std::os::raw::{c_int, c_void}; 81 | use std::thread; 82 | use std::thread::JoinHandle; 83 | 84 | const LOCAL_URI: &str = "127.0.0.1:31850"; 85 | 86 | extern "C" fn req_handler(req_handle: *mut ffi::ReqHandle, context: *mut c_void) -> () { 87 | println!("req_handler start"); 88 | let req_handle = ReqHandle::from_raw(req_handle); 89 | let s = req_handle.get_req_msgbuf(); 90 | println!("req: {}", String::from_utf8(s).expect("")); 91 | 92 | let c = AppContext::from_raw(context); 93 | let r = Rpc::from_context(&c); 94 | let s = "world".to_string().into_bytes(); 95 | r.enqueue_response(&req_handle, s); 96 | println!("req_handler end"); 97 | } 98 | 99 | extern "C" fn sm_handler( 100 | _session_num: c_int, 101 | _sm_event_type: ffi::SmEventType, 102 | _sm_err_type: ffi::SmErrType, 103 | _context: *mut c_void, 104 | ) { 105 | println!("sm_handler"); 106 | } 107 | 108 | fn main() { 109 | let nexus = Nexus::new(LOCAL_URI.to_string(), 0, 0); 110 | nexus.register_req_func(1, req_handler, 0); 111 | 112 | let mut wait_vec: Vec> = Vec::new(); 113 | 114 | let num_threads = 2; 115 | 116 | for i in 0..num_threads { 117 | let context = AppContext::new(); 118 | let nexus = nexus.clone(); 119 | 120 | let handle = thread::spawn(move || { 121 | let rpc = Rpc::new(&context, &nexus, i, sm_handler, 0); 122 | loop { 123 | rpc.run_event_loop(1000); 124 | } 125 | }); 126 | 127 | wait_vec.push(handle); 128 | } 129 | for handle in wait_vec { 130 | handle.join().unwrap(); 131 | } 132 | } 133 | ``` 134 | 135 | # Client 136 | ```rust,editable 137 | use erpc_rs::context::AppContext; 138 | use erpc_rs::msgbuffs; 139 | use erpc_rs::nexus::Nexus; 140 | use erpc_rs::rpc::Rpc; 141 | use erpc_sys::ffi; 142 | use std::os::raw::{c_int, c_void}; 143 | 144 | use msgbuffs::MsgBuffers; 145 | use std::thread; 146 | use std::thread::JoinHandle; 147 | 148 | const LOCAL_URI: &str = "127.0.0.1:31851"; 149 | const SERVER_URI: &str = "127.0.0.1:31850"; 150 | 151 | extern "C" fn sm_handler( 152 | session_num: c_int, 153 | sm_event_type: ffi::SmEventType, 154 | sm_err_type: ffi::SmErrType, 155 | context: *mut c_void, 156 | ) { 157 | println!( 158 | "sm_handler session_num: {} sm_event_type: {} sm_err_type: {}", 159 | session_num, sm_event_type, sm_err_type 160 | ); 161 | let _ctx: *mut ffi::AppContext = context as *mut ffi::AppContext; 162 | } 163 | 164 | extern "C" fn cont_func(_context: *mut c_void, tag: *mut c_void) { 165 | let context = AppContext::from_raw(_context); 166 | let tag = tag as usize; 167 | 168 | let msg_buffs = MsgBuffers::from_context(&context, tag); 169 | let s = msg_buffs.get_resp_msgbuf(); 170 | let s = String::from_utf8(s).expect(""); 171 | println!("cont_func tag: {} resp: {}", tag, s); 172 | 173 | let session_num = context.get_session_num(); 174 | let rpc = Rpc::from_context(&context); 175 | let s = "hello".to_string().into_bytes(); 176 | rpc.enqueue_request(&context, session_num, 1, s, cont_func, 1000, 0); 177 | } 178 | 179 | fn main() { 180 | let nexus = Nexus::new(LOCAL_URI.to_string(), 0, 0); 181 | 182 | let mut wait_vec: Vec> = Vec::new(); 183 | 184 | let num_threads = 2; 185 | 186 | for i in 0..num_threads { 187 | let context = AppContext::new(); 188 | let nexus = nexus.clone(); 189 | 190 | let handle = thread::spawn(move || { 191 | let rpc = Rpc::new(&context, &nexus, i, sm_handler, 0); 192 | 193 | let session_num = context.connect_session(SERVER_URI.to_string(), 0); 194 | 195 | println!("session_num: {}", session_num); 196 | 197 | while !rpc.is_connected(session_num) { 198 | rpc.run_event_loop_once(); 199 | } 200 | 201 | println!("connected"); 202 | 203 | loop { 204 | rpc.run_event_loop(1000); 205 | let s = "hello".to_string().into_bytes(); 206 | rpc.enqueue_request(&context, session_num, 1, s, cont_func, 0, 8); 207 | } 208 | }); 209 | 210 | wait_vec.push(handle); 211 | } 212 | 213 | for handle in wait_vec { 214 | handle.join().unwrap(); 215 | } 216 | } 217 | ``` 218 | -------------------------------------------------------------------------------- /erpc-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erpc-sys" 3 | version = "0.2.0" 4 | authors = ["Frank Zhou <529808348@qq.com>"] 5 | edition = "2018" 6 | keywords = ["erpc", "rpc", "rust", "ffi"] 7 | repository = "https://github.com/coinrust/erpc-rs" 8 | readme = "README.md" 9 | description = "The Rust FFI bindings of eRPC" 10 | license = "Apache-2.0" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | libc = "0.2" 16 | 17 | [build-dependencies] 18 | dirs = "2.0" 19 | cc = "1.0" 20 | -------------------------------------------------------------------------------- /erpc-sys/README.md: -------------------------------------------------------------------------------- 1 | # erpc-sys 2 | The Rust FFI bindings of eRPC -------------------------------------------------------------------------------- /erpc-sys/build.rs: -------------------------------------------------------------------------------- 1 | extern crate cc; 2 | extern crate dirs; 3 | 4 | use std::env; 5 | use std::path::Path; 6 | 7 | // ERPC_INFINIBAND=true cargo build 8 | // ERPC_RAW=true cargo build 9 | // ERPC_DPDK=true cargo build 10 | 11 | fn main() { 12 | let home_dir = dirs::home_dir().unwrap(); 13 | 14 | let mut erpc_flag: String = String::from("-DERPC_INFINIBAND=true"); 15 | 16 | match env::var("ERPC_INFINIBAND") { 17 | Ok(_val) => erpc_flag = String::from("-DERPC_INFINIBAND=true"), 18 | Err(_e) => (), 19 | } 20 | match env::var("ERPC_RAW") { 21 | Ok(_val) => erpc_flag = String::from("-DERPC_RAW=true"), 22 | Err(_e) => (), 23 | } 24 | match env::var("ERPC_DPDK") { 25 | Ok(_val) => erpc_flag = String::from("-DERPC_DPDK=true"), 26 | Err(_e) => (), 27 | } 28 | 29 | cc::Build::new() 30 | .cpp(true) 31 | .flag("-g") 32 | .flag("-std=c++11") // -std=c++1y 33 | .flag(erpc_flag.as_str()) // "-DERPC_INFINIBAND=true" 34 | .include(Path::new(&home_dir).join("eRPC/src")) 35 | .include(Path::new(&home_dir).join("junction-install/include")) 36 | .include("src") 37 | .file("src/ffi.cpp") 38 | .file("src/server.cpp") 39 | .file("src/client.cpp") 40 | .warnings(false) 41 | .compile("erpc_ffi"); 42 | 43 | println!( 44 | "cargo:rustc-link-search=native={}", 45 | Path::new(&home_dir).join("eRPC/build").display() 46 | ); 47 | println!( 48 | "cargo:rustc-link-search=native={}", 49 | Path::new(&home_dir).join("junction-install/lib").display() 50 | ); 51 | 52 | println!("cargo:rustc-link-lib=erpc"); 53 | println!("cargo:rustc-link-lib=pthread"); 54 | println!("cargo:rustc-link-lib=numa"); 55 | println!("cargo:rustc-link-lib=dl"); 56 | println!("cargo:rustc-link-lib=ibverbs"); 57 | 58 | println!("cargo:rustc-link-lib=junction"); 59 | println!("cargo:rustc-link-lib=turf"); 60 | 61 | println!("cargo:rerun-if-changed=src/client.cpp"); 62 | println!("cargo:rerun-if-changed=src/common.h"); 63 | println!("cargo:rerun-if-changed=src/ffi.cpp"); 64 | println!("cargo:rerun-if-changed=src/ffi.rs"); 65 | println!("cargo:rerun-if-changed=src/lib.rs"); 66 | println!("cargo:rerun-if-changed=src/server.cpp"); 67 | println!("cargo:rerun-if-changed=build.rs"); 68 | } 69 | 70 | /* 71 | # ~/eRPC/hello_world/Makefile 72 | 73 | #Notes: 74 | #1. The make target depends on how eRPC was compiled: 75 | # * If DTRANSPORT=dpdk, use `make dpdk` 76 | # * If DTRANSPORT=raw, use `make raw` 77 | # * If DTRANSPORT=infiniband, use `make infiniband` 78 | LIBS = -lerpc -lpthread -lnuma -ldl 79 | 80 | error: 81 | @echo "Please choose one of the following targets: infiniband, raw, dpdk, clean" 82 | @exit 2 83 | infiniband: 84 | g++ -g -std=c++11 -o server server.cc -I ../src -L ../build $(LIBS) -libverbs -DERPC_INFINIBAND=true 85 | g++ -g -std=c++11 -o client client.cc -I ../src -L ../build $(LIBS) -libverbs -DERPC_INFINIBAND=true 86 | raw: 87 | g++ -g -std=c++11 -o server server.cc -I ../src -L ../build $(LIBS) -libverbs -DERPC_RAW=true 88 | g++ -g -std=c++11 -o client client.cc -I ../src -L ../build $(LIBS) -libverbs -DERPC_RAW=true 89 | dpdk: 90 | g++ -g -std=c++11 -o server server.cc -I ../src -I /usr/local/include/dpdk -L ../build $(LIBS) -ldpdk -DERPC_DPDK=true -march=native 91 | g++ -g -std=c++11 -o client client.cc -I ../src -I /usr/local/include/dpdk -L ../build $(LIBS) -ldpdk -DERPC_DPDK=true -march=native 92 | clean: 93 | rm server client 94 | */ 95 | -------------------------------------------------------------------------------- /erpc-sys/src/client.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "rpc.h" 3 | #include "rpc_types.h" 4 | #include "transport_impl/eth_common.h" 5 | #include "util/latency.h" 6 | #include "util/numautils.h" 7 | #include 8 | #include 9 | 10 | extern "C" 11 | { 12 | 13 | void client_cont_func(void *_c, void *_tag) 14 | { 15 | printf("client_cont_func start\n"); 16 | auto tag = reinterpret_cast(_tag); 17 | auto *c = static_cast(_c); 18 | std::string s((const char *)c->resp.buf, c->resp.get_data_size()); 19 | printf("tag: %zu %s\n", tag, s.c_str()); 20 | printf("client_cont_func end\n"); 21 | } 22 | 23 | // A basic session management handler that expects successful responses 24 | void client_sm_handler(int session_num, erpc::SmEventType sm_event_type, 25 | erpc::SmErrType sm_err_type, void *_context) 26 | { 27 | auto *c = static_cast(_context); 28 | printf("client_sm_handler session_num: %d sm_event_type: %d sm_err_type: %d\n", 29 | session_num, (int)sm_event_type, (int)sm_err_type); 30 | } 31 | 32 | int connect_session(AppContext &c) 33 | { 34 | std::string server_uri = 35 | kServerHostname + ":" + std::to_string(kServerUDPPort); 36 | printf("connect session server_url: %s\n", server_uri.c_str()); 37 | 38 | int session_num = c.rpc->create_session(server_uri, 0 /* tid */); 39 | erpc::rt_assert(session_num >= 0, "Failed to create session"); 40 | 41 | while (!c.rpc->is_connected(session_num)) 42 | { 43 | c.rpc->run_event_loop_once(); 44 | } 45 | 46 | return session_num; 47 | } 48 | 49 | void send_q(AppContext *c) 50 | { 51 | auto kReqMsgSize = strlen("hello"); 52 | c->req = c->rpc->alloc_msg_buffer_or_die(kReqMsgSize); 53 | c->resp = c->rpc->alloc_msg_buffer_or_die(kMsgSize); 54 | 55 | sprintf(reinterpret_cast(c->req.buf), "%s", "hello"); 56 | 57 | c->rpc->enqueue_request(c->session_num, kReqType, &c->req, &c->resp, 58 | client_cont_func, nullptr); 59 | } 60 | 61 | void client_func(erpc::Nexus *nexus, size_t thread_id) 62 | { 63 | AppContext c; 64 | erpc::Rpc rpc(nexus, static_cast(&c), thread_id, 65 | client_sm_handler, 0); // phy_port 66 | rpc.retry_connect_on_invalid_rpc_id = true; 67 | c.rpc = &rpc; 68 | c.thread_id = thread_id; 69 | 70 | auto session_num = connect_session(c); 71 | printf("session_num %d\n", session_num); 72 | 73 | c.session_num = session_num; 74 | 75 | while (true) 76 | { 77 | rpc.run_event_loop(1000); 78 | send_q(&c); 79 | } 80 | } 81 | 82 | int client_test() 83 | { 84 | int num_threads = 2; 85 | std::string client_uri = 86 | kClientHostname + ":" + std::to_string(kClientUDPPort); 87 | erpc::Nexus nexus(client_uri, 0, 0); 88 | 89 | std::vector threads(num_threads); 90 | 91 | for (size_t i = 0; i < num_threads; i++) 92 | { 93 | threads[i] = std::thread(client_func, &nexus, i); 94 | erpc::bind_to_core(threads[i], 0, i); 95 | } 96 | 97 | for (size_t i = 0; i < num_threads; i++) 98 | threads[i].join(); 99 | return 0; 100 | } 101 | 102 | // int client_test_sample() { 103 | // std::string client_uri = kClientHostname + ":" + 104 | // std::to_string(kClientUDPPort); erpc::Nexus nexus(client_uri, 105 | // //erpc::get_uri_for_process(FLAGS_process_id), // FLAGS_process_id 106 | // 0, 0); // FLAGS_numa_node, 0 107 | // AppContext c; 108 | // erpc::Rpc rpc(&nexus, static_cast(&c), 0, 109 | // client_sm_handler, 0); // phy_port 110 | // rpc.retry_connect_on_invalid_rpc_id = true; 111 | // c.rpc = &rpc; 112 | // auto session_num = connect_session(c); 113 | 114 | // auto kMsgSize = strlen("hello"); 115 | // auto req = rpc.alloc_msg_buffer_or_die(kMsgSize); 116 | // auto resp = rpc.alloc_msg_buffer_or_die(kMsgSize); 117 | 118 | // sprintf(reinterpret_cast(req.buf), "%s", "hello"); 119 | 120 | // c.rpc->enqueue_request(session_num, kReqType, &req, 121 | // &resp, client_cont_func, nullptr); 122 | // rpc.run_event_loop(10000); 123 | // return 0; 124 | // } 125 | } 126 | -------------------------------------------------------------------------------- /erpc-sys/src/common.h: -------------------------------------------------------------------------------- 1 | #include "rpc.h" 2 | #include 3 | 4 | static const std::string kServerHostname = "127.0.0.1"; 5 | static const std::string kClientHostname = "127.0.0.1"; 6 | 7 | static constexpr uint16_t kServerUDPPort = 31850; 8 | static constexpr uint16_t kClientUDPPort = 31851; 9 | static constexpr uint8_t kReqType = 1; 10 | static constexpr size_t kMsgSize = 16; 11 | 12 | class AppContext { 13 | public: 14 | erpc::Rpc *rpc = nullptr; 15 | size_t thread_id; 16 | int session_num; 17 | erpc::MsgBuffer req; 18 | erpc::MsgBuffer resp; 19 | 20 | ~AppContext() {} 21 | }; 22 | -------------------------------------------------------------------------------- /erpc-sys/src/ffi.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc.h" 2 | #include "rpc_types.h" 3 | #include "transport_impl/eth_common.h" 4 | #include "util/latency.h" 5 | #include "util/numautils.h" 6 | #include 7 | #include 8 | #include 9 | 10 | class MsgBuffers { 11 | public: 12 | erpc::MsgBuffer req_msgbuf; 13 | erpc::MsgBuffer resp_msgbuf; 14 | }; 15 | 16 | typedef junction::ConcurrentMap_Leapfrog ConcurrentMap; 17 | 18 | class AppContext { 19 | public: 20 | erpc::Rpc *rpc = nullptr; 21 | int session_num = 0; 22 | ConcurrentMap msgbufs; 23 | 24 | ~AppContext() {} 25 | 26 | inline MsgBuffers *alloc_msg_buffer_or_die(size_t req_id, 27 | size_t req_max_data_size, 28 | size_t resp_max_data_size) { 29 | MsgBuffers *buffs = new MsgBuffers(); 30 | buffs->req_msgbuf = rpc->alloc_msg_buffer_or_die(req_max_data_size); 31 | buffs->resp_msgbuf = rpc->alloc_msg_buffer_or_die(resp_max_data_size); 32 | msgbufs.assign(req_id, buffs); 33 | return buffs; 34 | } 35 | }; 36 | 37 | extern "C" { 38 | 39 | erpc::Nexus *erpc_nexus_new(const char *local_uri, size_t numa_node, 40 | size_t num_bg_threads) { 41 | return new erpc::Nexus(local_uri, numa_node, num_bg_threads); 42 | } 43 | 44 | void erpc_nexus_destroy(erpc::Nexus *nexus) { 45 | if (nexus != nullptr) { 46 | delete nexus; 47 | nexus = nullptr; 48 | } 49 | } 50 | 51 | void erpc_nexus_register_req_func(erpc::Nexus *nexus, uint8_t req_type, 52 | erpc::erpc_req_func_t req_func, 53 | uint8_t req_func_type) { // ReqFuncType 54 | nexus->register_req_func(req_type, req_func, 55 | erpc::ReqFuncType(req_func_type)); 56 | } 57 | 58 | AppContext *app_context_new() { return new AppContext{}; } 59 | 60 | void app_context_destroy(AppContext *context) { 61 | if (context != nullptr) { 62 | delete context; 63 | context = nullptr; 64 | } 65 | } 66 | 67 | erpc::Rpc *app_context_rpc(AppContext *context) { 68 | return context->rpc; 69 | } 70 | 71 | int app_context_get_session_num(AppContext *context) { 72 | return context->session_num; 73 | } 74 | 75 | erpc::Rpc *erpc_rpc_new(erpc::Nexus *nexus, 76 | AppContext *context, uint8_t rpc_id, 77 | erpc::sm_handler_t sm_handler, 78 | uint8_t phy_port) { 79 | auto ret = new erpc::Rpc( 80 | nexus, static_cast(context), rpc_id, sm_handler, phy_port); 81 | ret->retry_connect_on_invalid_rpc_id = true; 82 | context->rpc = ret; 83 | return ret; 84 | } 85 | 86 | void erpc_rpc_destroy(erpc::Rpc *rpc) { 87 | if (rpc != nullptr) { 88 | delete rpc; 89 | rpc = nullptr; 90 | } 91 | } 92 | 93 | int erpc_connect_session(AppContext *context, const char *server_uri, 94 | uint8_t rem_rpc_id) { 95 | int session_num = context->rpc->create_session(server_uri, rem_rpc_id); 96 | //erpc::rt_assert(session_num >= 0, "Failed to create session"); 97 | // printf("session_num %d\n", session_num); 98 | context->session_num = session_num; 99 | return session_num; 100 | } 101 | 102 | bool erpc_rpc_is_connected(erpc::Rpc *rpc, int session_num) { 103 | return rpc->is_connected(session_num); 104 | } 105 | 106 | void erpc_run_event_loop_once(erpc::Rpc *rpc) { 107 | rpc->run_event_loop_once(); // size_t timeout_ms 108 | } 109 | 110 | void erpc_rpc_run_event_loop(erpc::Rpc *rpc, 111 | size_t timeout_ms) { 112 | rpc->run_event_loop(timeout_ms); // size_t timeout_ms 113 | } 114 | 115 | uint8_t *erpc_get_req_msgbuf(erpc::ReqHandle *req_handle, size_t &data_size) { 116 | auto msgbuf = req_handle->get_req_msgbuf(); 117 | data_size = msgbuf->get_data_size(); 118 | return msgbuf->buf; 119 | } 120 | 121 | void erpc_enqueue_request(AppContext *context, erpc::Rpc *rpc, 122 | int session_num, uint8_t req_type, 123 | const uint8_t *data, size_t data_size, 124 | erpc::erpc_cont_func_t cont_func, size_t tag, 125 | size_t cont_etid) { 126 | auto buffs = context->alloc_msg_buffer_or_die(tag, data_size, 1024); 127 | 128 | memcpy(buffs->req_msgbuf.buf, data, data_size); 129 | 130 | rpc->enqueue_request(session_num, 1, &buffs->req_msgbuf, &buffs->resp_msgbuf, 131 | cont_func, reinterpret_cast(tag)); // nullptr 132 | } 133 | 134 | void erpc_enqueue_response(erpc::Rpc *rpc, 135 | erpc::ReqHandle *req_handle, const uint8_t *data, 136 | size_t data_size) { 137 | auto &resp = req_handle->pre_resp_msgbuf; 138 | rpc->resize_msg_buffer(&resp, data_size); 139 | memcpy(resp.buf, data, data_size); 140 | 141 | rpc->enqueue_response(req_handle, &resp); 142 | } 143 | 144 | MsgBuffers *erpc_msgbuffs_get_by_tag(AppContext *context, size_t tag) { 145 | auto item = context->msgbufs.get(tag); 146 | if (item == nullptr) { 147 | return nullptr; 148 | } 149 | context->msgbufs.erase(tag); 150 | return item; 151 | } 152 | 153 | void erpc_msgbuffs_destroy(MsgBuffers *buffs) { 154 | if (buffs != nullptr) { 155 | delete buffs; 156 | buffs = nullptr; 157 | } 158 | } 159 | 160 | uint8_t *erpc_msgbuffs_req_msgbuf(MsgBuffers *buffs, size_t &data_size) { 161 | data_size = buffs->req_msgbuf.get_data_size(); 162 | return buffs->req_msgbuf.buf; 163 | } 164 | 165 | uint8_t *erpc_msgbuffs_resp_msgbuf(MsgBuffers *buffs, size_t &data_size) { 166 | data_size = buffs->resp_msgbuf.get_data_size(); 167 | return buffs->resp_msgbuf.buf; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /erpc-sys/src/ffi.rs: -------------------------------------------------------------------------------- 1 | use libc::size_t; 2 | use std::os::raw::{c_char, c_int, c_void}; 3 | 4 | pub enum Nexus {} // erpc::Nexus 5 | pub enum ReqHandle {} // erpc::ReqHandle 6 | pub enum AppContext {} // AppContext 7 | pub enum MsgBuffers {} // MsgBuffers 8 | pub enum Rpc {} // erpc::Rpc 9 | 10 | /// The types of responses to a session management packet 11 | //enum class SmErrType : int 12 | 13 | #[doc = "< The only non-error error type"] 14 | pub const SM_ERR_TYPE_K_NO_ERROR: SmErrType = 0; 15 | #[doc = "< The control-path connection to the server failed"] 16 | pub const SM_ERR_TYPE_K_SRV_DISCONNECTED: SmErrType = 1; 17 | #[doc = "< Connect req failed because server is out of ring bufs"] 18 | pub const SM_ERR_TYPE_K_RING_EXHAUSTED: SmErrType = 2; 19 | #[doc = "< Connect req failed because server is out of memory"] 20 | pub const SM_ERR_TYPE_K_OUT_OF_MEMORY: SmErrType = 3; 21 | #[doc = "< Server failed to resolve client routing info"] 22 | pub const SM_ERR_TYPE_K_ROUTING_RESOLUTION_FAILURE: SmErrType = 4; 23 | #[doc = "< Connect req failed because remote RPC ID was wrong"] 24 | pub const SM_ERR_TYPE_K_INVALID_REMOTE_RPC_ID: SmErrType = 5; 25 | #[doc = "< Connect req failed because of transport mismatch"] 26 | pub const SM_ERR_TYPE_K_INVALID_TRANSPORT: SmErrType = 6; 27 | pub type SmErrType = i32; 28 | 29 | /// Events generated for application-level session management handler 30 | //enum class SmEventType 31 | 32 | pub const SM_EVENT_TYPE_K_CONNECTED: SmEventType = 0; 33 | pub const SM_EVENT_TYPE_K_CONNECT_FAILED: SmEventType = 1; 34 | pub const SM_EVENT_TYPE_K_DISCONNECTED: SmEventType = 2; 35 | pub const SM_EVENT_TYPE_K_DISCONNECT_FAILED: SmEventType = 3; 36 | pub type SmEventType = u32; 37 | 38 | #[allow(dead_code)] 39 | extern "C" fn sample_req_handler(_req_handle: *mut ReqHandle, _context: *mut c_void) -> () {} 40 | 41 | #[allow(dead_code)] 42 | extern "C" fn sample_sm_handler( 43 | _session_num: c_int, 44 | _sm_event_type: SmEventType, 45 | _sm_err_type: SmErrType, 46 | _context: *mut c_void, 47 | ) { 48 | } 49 | 50 | #[allow(dead_code)] 51 | extern "C" fn sample_cont_func(_context: *mut c_void, _tag: *mut c_void) {} 52 | 53 | #[allow(dead_code)] 54 | extern "C" { 55 | pub fn erpc_nexus_new( 56 | local_uri: *const c_char, 57 | numa_node: size_t, 58 | num_bg_threads: size_t, 59 | ) -> *mut Nexus; 60 | pub fn erpc_nexus_destroy(nexus: *mut Nexus) -> (); 61 | 62 | // erpc::erpc_req_func_t 63 | pub fn erpc_nexus_register_req_func( 64 | nexus: *mut Nexus, 65 | req_type: u8, 66 | req_func: extern "C" fn(*mut ReqHandle, *mut c_void) -> (), 67 | req_func_type: u8, 68 | ); 69 | 70 | pub fn app_context_new() -> *mut AppContext; 71 | pub fn app_context_destroy(ctx: *mut AppContext) -> (); 72 | pub fn app_context_rpc(context: *mut AppContext) -> *mut Rpc; 73 | pub fn app_context_get_session_num(context: *mut AppContext) -> i32; 74 | 75 | pub fn erpc_rpc_new( 76 | nexus: *mut Nexus, 77 | context: *mut AppContext, 78 | rpc_id: u8, 79 | sm_handler: extern "C" fn(c_int, SmEventType, SmErrType, *mut c_void), 80 | phy_port: u8, 81 | ) -> *mut Rpc; 82 | pub fn erpc_rpc_destroy(rpc: *mut Rpc) -> (); 83 | pub fn erpc_connect_session( 84 | context: *mut AppContext, 85 | server_uri: *const c_char, 86 | rem_rpc_id: u8, 87 | ) -> c_int; 88 | pub fn erpc_rpc_is_connected(rpc: *mut Rpc, session_num: c_int) -> bool; 89 | pub fn erpc_run_event_loop_once(rpc: *mut Rpc) -> (); 90 | pub fn erpc_rpc_run_event_loop(rpc: *mut Rpc, timeout_ms: size_t) -> (); 91 | 92 | pub fn erpc_get_req_msgbuf(req_handle: *mut ReqHandle, data_size: &size_t) -> *mut u8; 93 | pub fn erpc_enqueue_request( 94 | context: *mut AppContext, 95 | rpc: *mut Rpc, 96 | session_num: c_int, 97 | req_type: u8, 98 | data: *const u8, 99 | data_size: size_t, 100 | cont_func: extern "C" fn(*mut c_void, *mut c_void), 101 | tag: size_t, 102 | cont_etid: size_t, 103 | ) -> (); 104 | pub fn erpc_enqueue_response( 105 | rpc: *mut Rpc, 106 | req_handle: *mut ReqHandle, 107 | data: *const u8, 108 | data_size: size_t, 109 | ) -> (); 110 | 111 | pub fn erpc_msgbuffs_get_by_tag(context: *mut AppContext, tag: size_t) -> *mut MsgBuffers; 112 | pub fn erpc_msgbuffs_destroy(buffs: *mut MsgBuffers) -> (); 113 | pub fn erpc_msgbuffs_req_msgbuf(buffs: *mut MsgBuffers, data_size: &size_t) -> *mut u8; 114 | pub fn erpc_msgbuffs_resp_msgbuf(buffs: *mut MsgBuffers, data_size: &size_t) -> *mut u8; 115 | 116 | pub fn server_test() -> c_int; 117 | pub fn client_test() -> c_int; 118 | } 119 | -------------------------------------------------------------------------------- /erpc-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ffi; 2 | 3 | #[cfg(test)] 4 | mod tests { 5 | use crate::ffi::server_test; 6 | 7 | #[test] 8 | fn it_works() { 9 | assert_eq!(2 + 2, 4); 10 | } 11 | 12 | #[test] 13 | fn f() { 14 | unsafe { 15 | server_test(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /erpc-sys/src/server.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "util/numautils.h" 3 | 4 | void req_handler(erpc::ReqHandle *req_handle, void *context) 5 | { 6 | printf("req_handler start\n"); 7 | AppContext *c = static_cast(context); 8 | auto req_msgbuf = req_handle->get_req_msgbuf(); 9 | std::string s((const char *)req_msgbuf->buf, req_msgbuf->get_data_size()); 10 | printf("%s\n", s.c_str()); 11 | erpc::MsgBuffer *resp = &req_handle->pre_resp_msgbuf; 12 | auto kMsgSize = strlen("world"); 13 | c->rpc->resize_msg_buffer(resp, kMsgSize); 14 | sprintf(reinterpret_cast(resp->buf), "world"); 15 | 16 | c->rpc->enqueue_response(req_handle, resp); 17 | printf("req_handler end\n"); 18 | } 19 | 20 | void basic_sm_handler(int session_num, erpc::SmEventType sm_event_type, 21 | erpc::SmErrType sm_err_type, void *_context) 22 | { 23 | printf("basic_sm_handler\n"); 24 | } 25 | 26 | void server_func(erpc::Nexus *nexus, size_t thread_id) 27 | { 28 | AppContext c; 29 | erpc::Rpc *rpc = new erpc::Rpc( 30 | nexus, static_cast(&c), thread_id, basic_sm_handler); 31 | c.rpc = rpc; 32 | while (true) 33 | { 34 | rpc->run_event_loop(1000); 35 | } 36 | } 37 | 38 | extern "C" 39 | { 40 | int server_test() 41 | { 42 | int num_threads = 2; 43 | std::string server_uri = 44 | kServerHostname + ":" + std::to_string(kServerUDPPort); 45 | printf("server_uri: %s\n", server_uri.c_str()); 46 | erpc::Nexus nexus(server_uri, 0, 0); 47 | nexus.register_req_func(kReqType, req_handler); 48 | 49 | std::vector threads(num_threads); 50 | 51 | for (size_t i = 0; i < num_threads; i++) 52 | { 53 | threads[i] = std::thread(server_func, &nexus, i); 54 | erpc::bind_to_core(threads[i], 0, i); 55 | } 56 | 57 | for (size_t i = 0; i < num_threads; i++) 58 | threads[i].join(); 59 | } 60 | } -------------------------------------------------------------------------------- /examples/client.rs: -------------------------------------------------------------------------------- 1 | use erpc_rs::context::AppContext; 2 | use erpc_rs::msgbuffs; 3 | use erpc_rs::nexus::Nexus; 4 | use erpc_rs::rpc::Rpc; 5 | use erpc_sys::ffi; 6 | use std::os::raw::{c_int, c_void}; 7 | 8 | use msgbuffs::MsgBuffers; 9 | use std::thread; 10 | use std::thread::JoinHandle; 11 | 12 | const LOCAL_URI: &str = "127.0.0.1:31851"; 13 | const SERVER_URI: &str = "127.0.0.1:31850"; 14 | 15 | extern "C" fn sm_handler( 16 | session_num: c_int, 17 | sm_event_type: ffi::SmEventType, 18 | sm_err_type: ffi::SmErrType, 19 | context: *mut c_void, 20 | ) { 21 | println!( 22 | "sm_handler session_num: {} sm_event_type: {} sm_err_type: {}", 23 | session_num, sm_event_type, sm_err_type 24 | ); 25 | let _ctx: *mut ffi::AppContext = context as *mut ffi::AppContext; 26 | } 27 | 28 | extern "C" fn cont_func(_context: *mut c_void, tag: *mut c_void) { 29 | println!("cont_func start"); 30 | let context = AppContext::from_raw(_context); 31 | let tag = tag as usize; 32 | 33 | let msg_buffs = MsgBuffers::from_context(&context, tag); 34 | let s = msg_buffs.get_resp_msgbuf(); 35 | let s = String::from_utf8(s).expect(""); 36 | println!("cont_func tag: {} resp: {}", tag, s); 37 | 38 | println!("cont_func end"); 39 | } 40 | 41 | fn main() { 42 | let nexus = Nexus::new(LOCAL_URI.to_string(), 0, 0); 43 | 44 | let mut wait_vec: Vec> = Vec::new(); 45 | 46 | let num_threads = 2; 47 | 48 | for i in 0..num_threads { 49 | let context = AppContext::new(); 50 | let nexus = nexus.clone(); 51 | 52 | let handle = thread::spawn(move || { 53 | let rpc = Rpc::new(&context, &nexus, i, sm_handler, 0); 54 | 55 | let session_num = context.connect_session(SERVER_URI.to_string(), 0); 56 | 57 | println!("session_num: {}", session_num); 58 | 59 | while !rpc.is_connected(session_num) { 60 | rpc.run_event_loop_once(); 61 | } 62 | 63 | println!("connected"); 64 | 65 | loop { 66 | rpc.run_event_loop(1000); 67 | let s = "hello".to_string().into_bytes(); 68 | rpc.enqueue_request(&context, session_num, 1, s, cont_func, 0, 8); 69 | } 70 | }); 71 | 72 | wait_vec.push(handle); 73 | } 74 | 75 | for handle in wait_vec { 76 | handle.join().unwrap(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /examples/client_raw.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi; 2 | use libc::size_t; 3 | use std::ffi::CString; 4 | use std::os::raw::{c_int, c_void}; 5 | 6 | const LOCAL_URI: &str = "127.0.0.1:31851"; 7 | const SERVER_URI: &str = "127.0.0.1:31850"; 8 | 9 | extern "C" fn sm_handler_raw( 10 | session_num: c_int, 11 | sm_event_type: ffi::SmEventType, 12 | sm_err_type: ffi::SmErrType, 13 | context: *mut c_void, 14 | ) { 15 | println!( 16 | "sm_handler session_num: {} sm_event_type: {} sm_err_type: {}", 17 | session_num, sm_event_type, sm_err_type 18 | ); 19 | let _ctx: *mut ffi::AppContext = context as *mut ffi::AppContext; 20 | } 21 | 22 | extern "C" fn cont_func(_context: *mut c_void, _tag: *mut c_void) { 23 | let ctx: *mut ffi::AppContext = _context as *mut ffi::AppContext; 24 | let tag = _tag as size_t; 25 | 26 | let data: *mut u8; 27 | let data_size: size_t = 0; 28 | let msgbufs = unsafe { ffi::erpc_msgbuffs_get_by_tag(ctx, tag) }; 29 | data = unsafe { ffi::erpc_msgbuffs_resp_msgbuf(msgbufs, &data_size) }; 30 | 31 | let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 32 | println!("cont_func tag: {} resp: {}", tag, s); 33 | 34 | unsafe { ffi::erpc_msgbuffs_destroy(msgbufs) }; 35 | } 36 | 37 | fn main() { 38 | unsafe { 39 | let context = ffi::app_context_new(); 40 | 41 | let local_uri = CString::new(LOCAL_URI).unwrap(); 42 | let nexus = ffi::erpc_nexus_new(local_uri.as_ptr(), 0, 0); 43 | let rpc = ffi::erpc_rpc_new(nexus, context, 0, sm_handler_raw, 0); 44 | 45 | let server_uri = CString::new(SERVER_URI).unwrap(); 46 | let session_num = ffi::erpc_connect_session(context, server_uri.as_ptr(), 0); 47 | println!("session_num: {}", session_num); 48 | 49 | // while (!rpc->is_connected(session_num)) rpc->run_event_loop_once(); 50 | while !ffi::erpc_rpc_is_connected(rpc, session_num) { 51 | ffi::erpc_run_event_loop_once(rpc); 52 | } 53 | println!("connected"); 54 | 55 | let s = "hello".to_string(); 56 | ffi::erpc_enqueue_request( 57 | context, 58 | rpc, 59 | session_num, 60 | 1, 61 | s.as_ptr(), 62 | s.len(), 63 | cont_func, 64 | 1000, 65 | 0, 66 | ); 67 | 68 | ffi::erpc_rpc_run_event_loop(rpc, 1000 * 5); 69 | 70 | ffi::erpc_rpc_destroy(rpc); 71 | ffi::erpc_nexus_destroy(nexus); 72 | ffi::app_context_destroy(context); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /examples/client_test.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi; 2 | 3 | fn main() { 4 | unsafe { 5 | ffi::client_test(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/server.rs: -------------------------------------------------------------------------------- 1 | use erpc_rs::context::AppContext; 2 | use erpc_rs::nexus::Nexus; 3 | use erpc_rs::reqhandle::ReqHandle; 4 | use erpc_rs::rpc::Rpc; 5 | use erpc_sys::ffi; 6 | use std::os::raw::{c_int, c_void}; 7 | use std::thread; 8 | use std::thread::JoinHandle; 9 | 10 | const LOCAL_URI: &str = "127.0.0.1:31850"; 11 | 12 | extern "C" fn req_handler(req_handle: *mut ffi::ReqHandle, context: *mut c_void) -> () { 13 | println!("req_handler start"); 14 | let req_handle = ReqHandle::from_raw(req_handle); 15 | let s = req_handle.get_req_msgbuf(); 16 | println!("req: {}", String::from_utf8(s).expect("")); 17 | 18 | let c = AppContext::from_raw(context); 19 | let r = Rpc::from_context(&c); 20 | let s = "world".to_string().into_bytes(); 21 | r.enqueue_response(&req_handle, s); 22 | println!("req_handler end"); 23 | } 24 | 25 | extern "C" fn sm_handler( 26 | _session_num: c_int, 27 | _sm_event_type: ffi::SmEventType, 28 | _sm_err_type: ffi::SmErrType, 29 | _context: *mut c_void, 30 | ) { 31 | println!("sm_handler"); 32 | } 33 | 34 | fn main() { 35 | let nexus = Nexus::new(LOCAL_URI.to_string(), 0, 0); 36 | nexus.register_req_func(1, req_handler, 0); 37 | 38 | let mut wait_vec: Vec> = Vec::new(); 39 | 40 | let num_threads = 2; 41 | 42 | for i in 0..num_threads { 43 | let context = AppContext::new(); 44 | let nexus = nexus.clone(); 45 | 46 | let handle = thread::spawn(move || { 47 | let rpc = Rpc::new(&context, &nexus, i, sm_handler, 0); 48 | loop { 49 | rpc.run_event_loop(1000); 50 | } 51 | }); 52 | 53 | wait_vec.push(handle); 54 | } 55 | for handle in wait_vec { 56 | handle.join().unwrap(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/server_raw.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi; 2 | use libc::size_t; 3 | use std::ffi::CString; 4 | use std::os::raw::{c_int, c_void}; 5 | 6 | const LOCAL_URI: &str = "127.0.0.1:31850"; 7 | 8 | extern "C" fn req_handler(req_handle: *mut ffi::ReqHandle, context: *mut c_void) -> () { 9 | println!("req_handler start"); 10 | let data: *mut u8; 11 | let data_size: size_t = 0; 12 | unsafe { data = ffi::erpc_get_req_msgbuf(req_handle, &data_size) }; 13 | //println!("data_size: {:?} {}", data, data_size); 14 | 15 | let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 16 | println!("req: {}", s); 17 | 18 | let ctx: *mut ffi::AppContext = context as *mut ffi::AppContext; 19 | let _rpc = unsafe { ffi::app_context_rpc(ctx) }; 20 | let s = "world".to_string(); 21 | unsafe { ffi::erpc_enqueue_response(_rpc, req_handle, s.as_ptr(), s.len()) }; 22 | println!("req_handler end"); 23 | } 24 | 25 | extern "C" fn sm_handler( 26 | _session_num: c_int, 27 | _sm_event_type: ffi::SmEventType, 28 | _sm_err_type: ffi::SmErrType, 29 | _context: *mut c_void, 30 | ) { 31 | println!("sm_handler"); 32 | } 33 | 34 | // sudo rxe_cfg start 35 | // sudo rxe_cfg status 36 | 37 | fn main() { 38 | unsafe { 39 | let context = ffi::app_context_new(); 40 | 41 | let local_uri = CString::new(LOCAL_URI).unwrap(); 42 | let nexus = ffi::erpc_nexus_new(local_uri.as_ptr(), 0, 0); 43 | ffi::erpc_nexus_register_req_func(nexus, 1, req_handler, 0); 44 | let rpc = ffi::erpc_rpc_new(nexus, context, 0, sm_handler, 0); 45 | 46 | loop { 47 | ffi::erpc_rpc_run_event_loop(rpc, 1000); 48 | } 49 | 50 | //ffi::erpc_rpc_destroy(rpc); 51 | //ffi::erpc_nexus_destroy(nexus); 52 | //ffi::app_context_destroy(context); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/server_test.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi; 2 | 3 | fn main() { 4 | unsafe { 5 | ffi::server_test(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi::{self}; 2 | use std::ffi::CString; 3 | use std::os::raw::c_void; 4 | 5 | pub struct AppContext { 6 | pub inner: *mut ffi::AppContext, 7 | owner: bool, 8 | } 9 | 10 | impl Clone for AppContext { 11 | fn clone(&self) -> AppContext { 12 | AppContext { 13 | inner: self.inner, 14 | owner: false, 15 | } 16 | } 17 | } 18 | 19 | unsafe impl Send for AppContext {} 20 | 21 | impl AppContext { 22 | pub fn new() -> Self { 23 | AppContext { 24 | inner: unsafe { ffi::app_context_new() }, 25 | owner: true, 26 | } 27 | } 28 | 29 | pub fn from_raw(context: *mut c_void) -> Self { 30 | let context: *mut ffi::AppContext = context as *mut ffi::AppContext; 31 | AppContext { 32 | inner: context, 33 | owner: false, 34 | } 35 | } 36 | 37 | pub fn get_session_num(&self) -> i32 { 38 | unsafe { ffi::app_context_get_session_num(self.inner) } 39 | } 40 | 41 | pub fn connect_session(&self, server_uri: String, rem_rpc_id: u8) -> i32 { 42 | let server_uri = CString::new(server_uri).expect(""); 43 | unsafe { ffi::erpc_connect_session(self.inner, server_uri.as_ptr(), rem_rpc_id) } 44 | } 45 | 46 | // pub fn get_resp_msgbuf(&self, tag: usize) -> Vec { 47 | // let data: *mut u8; 48 | // let data_size : usize = 0; 49 | // unsafe { data = ffi::erpc_get_resp_msgbuf(self.inner, tag, &data_size) }; 50 | // //println!("data_size: {:?} {}", data, data_size); 51 | 52 | // let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 53 | // s.into_bytes() 54 | // } 55 | } 56 | 57 | impl Drop for AppContext { 58 | fn drop(&mut self) { 59 | if self.owner { 60 | unsafe { ffi::app_context_destroy(self.inner) } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod context; 2 | pub mod msgbuffs; 3 | pub mod nexus; 4 | pub mod reqhandle; 5 | pub mod rpc; 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn it_works() { 11 | assert_eq!(2 + 2, 4); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/msgbuffs.rs: -------------------------------------------------------------------------------- 1 | use crate::context::AppContext; 2 | use erpc_sys::ffi::{self}; 3 | 4 | pub struct MsgBuffers { 5 | pub inner: *mut ffi::MsgBuffers, 6 | } 7 | 8 | impl MsgBuffers { 9 | pub fn from_context(context: &AppContext, tag: usize) -> Self { 10 | let msg_buffs = unsafe { ffi::erpc_msgbuffs_get_by_tag(context.inner, tag) }; 11 | MsgBuffers { inner: msg_buffs } 12 | } 13 | 14 | pub fn get_req_msgbuf(&self) -> Vec { 15 | let data: *mut u8; 16 | let data_size: usize = 0; 17 | unsafe { data = ffi::erpc_msgbuffs_req_msgbuf(self.inner, &data_size) }; 18 | 19 | let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 20 | s.into_bytes() 21 | } 22 | 23 | pub fn get_resp_msgbuf(&self) -> Vec { 24 | let data: *mut u8; 25 | let data_size: usize = 0; 26 | unsafe { data = ffi::erpc_msgbuffs_resp_msgbuf(self.inner, &data_size) }; 27 | 28 | let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 29 | s.into_bytes() 30 | } 31 | } 32 | 33 | impl Drop for MsgBuffers { 34 | fn drop(&mut self) { 35 | unsafe { ffi::erpc_msgbuffs_destroy(self.inner) } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/nexus.rs: -------------------------------------------------------------------------------- 1 | use erpc_sys::ffi::{self}; 2 | use std::ffi::CString; 3 | use std::os::raw::c_void; 4 | 5 | pub struct Nexus { 6 | pub inner: *mut ffi::Nexus, 7 | owner: bool, 8 | } 9 | 10 | impl Clone for Nexus { 11 | fn clone(&self) -> Nexus { 12 | Nexus { 13 | inner: self.inner, 14 | owner: false, 15 | } 16 | } 17 | } 18 | 19 | unsafe impl Send for Nexus {} 20 | 21 | impl Nexus { 22 | pub fn new(local_uri: String, numa_node: usize, num_bg_threads: usize) -> Self { 23 | let local_uri = CString::new(local_uri).expect(""); 24 | Nexus { 25 | inner: unsafe { ffi::erpc_nexus_new(local_uri.as_ptr(), numa_node, num_bg_threads) }, 26 | owner: true, 27 | } 28 | } 29 | 30 | pub fn register_req_func( 31 | &self, 32 | req_type: u8, 33 | req_func: extern "C" fn(*mut ffi::ReqHandle, *mut c_void) -> (), 34 | req_func_type: u8, 35 | ) { 36 | unsafe { ffi::erpc_nexus_register_req_func(self.inner, req_type, req_func, req_func_type) } 37 | } 38 | } 39 | 40 | impl Drop for Nexus { 41 | fn drop(&mut self) { 42 | if self.owner { 43 | unsafe { ffi::erpc_nexus_destroy(self.inner) } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/reqhandle.rs: -------------------------------------------------------------------------------- 1 | use crate::context::AppContext; 2 | use crate::rpc::Rpc; 3 | use erpc_sys::ffi::{self}; 4 | 5 | pub struct ReqHandle { 6 | pub inner: *mut ffi::ReqHandle, 7 | } 8 | 9 | impl ReqHandle { 10 | pub fn from_raw(req_handle: *mut ffi::ReqHandle) -> Self { 11 | ReqHandle { inner: req_handle } 12 | } 13 | 14 | pub fn get_req_msgbuf(&self) -> Vec { 15 | let data: *mut u8; 16 | let data_size: usize = 0; 17 | unsafe { data = ffi::erpc_get_req_msgbuf(self.inner, &data_size) }; 18 | //println!("data_size: {:?} {}", data, data_size); 19 | let s = unsafe { String::from_raw_parts(data, data_size, 0) }; 20 | s.into_bytes() 21 | } 22 | 23 | pub fn enqueue_response(&self, context: &AppContext, data: Vec) -> () { 24 | let r = Rpc::from_context(&context); 25 | r.enqueue_response(self, data); 26 | } 27 | } 28 | 29 | impl Drop for ReqHandle { 30 | fn drop(&mut self) {} 31 | } 32 | -------------------------------------------------------------------------------- /src/rpc.rs: -------------------------------------------------------------------------------- 1 | use crate::context::AppContext; 2 | use crate::nexus::Nexus; 3 | use crate::reqhandle::ReqHandle; 4 | use erpc_sys::ffi::{self}; 5 | use std::os::raw::{c_int, c_void}; 6 | 7 | pub struct Rpc { 8 | inner: *mut ffi::Rpc, 9 | owner: bool, 10 | } 11 | 12 | impl Clone for Rpc { 13 | fn clone(&self) -> Rpc { 14 | Rpc { 15 | inner: self.inner, 16 | owner: false, 17 | } 18 | } 19 | } 20 | 21 | unsafe impl Send for Rpc {} 22 | 23 | impl Rpc { 24 | pub fn new( 25 | context: &AppContext, 26 | nexus: &Nexus, 27 | rpc_id: u8, 28 | sm_handler: extern "C" fn(c_int, ffi::SmEventType, ffi::SmErrType, *mut c_void), 29 | phy_port: u8, 30 | ) -> Self { 31 | let rpc = 32 | unsafe { ffi::erpc_rpc_new(nexus.inner, context.inner, rpc_id, sm_handler, phy_port) }; 33 | Rpc { 34 | inner: rpc, 35 | owner: true, 36 | } 37 | } 38 | 39 | pub fn from_context(context: &AppContext) -> Self { 40 | let rpc = unsafe { ffi::app_context_rpc(context.inner) }; 41 | Rpc { 42 | inner: rpc, 43 | owner: false, 44 | } 45 | } 46 | 47 | pub fn is_connected(&self, session_num: i32) -> bool { 48 | unsafe { ffi::erpc_rpc_is_connected(self.inner, session_num) } 49 | } 50 | 51 | pub fn run_event_loop_once(&self) -> () { 52 | unsafe { ffi::erpc_run_event_loop_once(self.inner) }; 53 | } 54 | 55 | pub fn run_event_loop(&self, timeout_ms: usize) -> () { 56 | unsafe { ffi::erpc_rpc_run_event_loop(self.inner, timeout_ms) }; 57 | } 58 | 59 | pub fn enqueue_request( 60 | &self, 61 | context: &AppContext, 62 | session_num: i32, 63 | req_type: u8, 64 | data: Vec, 65 | cont_func: extern "C" fn(*mut c_void, *mut c_void), 66 | tag: usize, 67 | cont_etid: usize, 68 | ) -> () { 69 | unsafe { 70 | ffi::erpc_enqueue_request( 71 | context.inner, 72 | self.inner, 73 | session_num, 74 | req_type, 75 | data.as_ptr(), 76 | data.len(), 77 | cont_func, 78 | tag, 79 | cont_etid, 80 | ) 81 | } 82 | } 83 | 84 | pub fn enqueue_response(&self, req_handle: &ReqHandle, data: Vec) -> () { 85 | unsafe { 86 | ffi::erpc_enqueue_response(self.inner, req_handle.inner, data.as_ptr(), data.len()) 87 | } 88 | } 89 | } 90 | 91 | impl Drop for Rpc { 92 | fn drop(&mut self) { 93 | if self.owner { 94 | unsafe { ffi::erpc_rpc_destroy(self.inner) } 95 | } 96 | } 97 | } 98 | --------------------------------------------------------------------------------