ext.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. *
  5. * (c) ZeroTier, Inc.
  6. * https://www.zerotier.com/
  7. */
  8. use std::ffi::{CStr, CString};
  9. use std::os::raw::c_char;
  10. #[cfg(feature = "ztcontroller")]
  11. use tokio::runtime;
  12. use url::Url;
  13. #[cfg(feature = "ztcontroller")]
  14. static mut RT: Option<tokio::runtime::Runtime> = None;
  15. #[cfg(feature = "ztcontroller")]
  16. static START: std::sync::Once = std::sync::Once::new();
  17. #[cfg(feature = "ztcontroller")]
  18. static SHUTDOWN: std::sync::Once = std::sync::Once::new();
  19. #[cfg(feature = "ztcontroller")]
  20. #[no_mangle]
  21. pub unsafe extern "C" fn init_async_runtime() {
  22. START.call_once(|| {
  23. let rt = runtime::Builder::new_multi_thread()
  24. .worker_threads(4)
  25. .thread_name("rust-async-worker")
  26. .enable_all()
  27. .build()
  28. .expect("Failed to create tokio runtime");
  29. unsafe { RT = Some(rt) };
  30. });
  31. }
  32. #[cfg(feature = "ztcontroller")]
  33. #[no_mangle]
  34. #[allow(static_mut_refs)]
  35. pub unsafe extern "C" fn shutdown_async_runtime() {
  36. SHUTDOWN.call_once(|| {
  37. // Shutdown the tokio runtime
  38. unsafe {
  39. if let Some(rt) = RT.take() {
  40. rt.shutdown_timeout(std::time::Duration::from_secs(5));
  41. }
  42. }
  43. });
  44. }
  45. #[cfg(feature = "zeroidc")]
  46. use crate::zeroidc::ZeroIDC;
  47. #[cfg(all(
  48. feature = "zeroidc",
  49. any(
  50. all(target_os = "linux", target_arch = "x86"),
  51. all(target_os = "linux", target_arch = "x86_64"),
  52. all(target_os = "linux", target_arch = "aarch64"),
  53. target_os = "windows",
  54. target_os = "macos",
  55. )
  56. ))]
  57. #[no_mangle]
  58. pub unsafe extern "C" fn zeroidc_new(
  59. issuer: *const c_char,
  60. client_id: *const c_char,
  61. auth_endpoint: *const c_char,
  62. provider: *const c_char,
  63. web_listen_port: u16,
  64. ) -> *mut ZeroIDC {
  65. if issuer.is_null() {
  66. println!("issuer is null");
  67. return std::ptr::null_mut();
  68. }
  69. if client_id.is_null() {
  70. println!("client_id is null");
  71. return std::ptr::null_mut();
  72. }
  73. if provider.is_null() {
  74. println!("provider is null");
  75. return std::ptr::null_mut();
  76. }
  77. if auth_endpoint.is_null() {
  78. println!("auth_endpoint is null");
  79. return std::ptr::null_mut();
  80. }
  81. let issuer = unsafe { CStr::from_ptr(issuer) };
  82. let client_id = unsafe { CStr::from_ptr(client_id) };
  83. let provider = unsafe { CStr::from_ptr(provider) };
  84. let auth_endpoint = unsafe { CStr::from_ptr(auth_endpoint) };
  85. match ZeroIDC::new(
  86. issuer.to_str().unwrap(),
  87. client_id.to_str().unwrap(),
  88. provider.to_str().unwrap(),
  89. auth_endpoint.to_str().unwrap(),
  90. web_listen_port,
  91. ) {
  92. Ok(idc) => Box::into_raw(Box::new(idc)),
  93. Err(s) => {
  94. println!("Error creating ZeroIDC instance: {}", s);
  95. std::ptr::null_mut()
  96. }
  97. }
  98. }
  99. #[cfg(all(
  100. feature = "zeroidc",
  101. any(
  102. all(target_os = "linux", target_arch = "x86"),
  103. all(target_os = "linux", target_arch = "x86_64"),
  104. all(target_os = "linux", target_arch = "aarch64"),
  105. target_os = "windows",
  106. target_os = "macos",
  107. )
  108. ))]
  109. #[no_mangle]
  110. pub unsafe extern "C" fn zeroidc_delete(ptr: *mut ZeroIDC) {
  111. if ptr.is_null() {
  112. return;
  113. }
  114. let idc = unsafe {
  115. assert!(!ptr.is_null());
  116. &mut *ptr
  117. };
  118. idc.stop();
  119. unsafe {
  120. let _ = Box::from_raw(ptr);
  121. }
  122. }
  123. #[cfg(all(
  124. feature = "zeroidc",
  125. any(
  126. all(target_os = "linux", target_arch = "x86"),
  127. all(target_os = "linux", target_arch = "x86_64"),
  128. all(target_os = "linux", target_arch = "aarch64"),
  129. target_os = "windows",
  130. target_os = "macos",
  131. )
  132. ))]
  133. #[no_mangle]
  134. pub unsafe extern "C" fn zeroidc_start(ptr: *mut ZeroIDC) {
  135. let idc = unsafe {
  136. assert!(!ptr.is_null());
  137. &mut *ptr
  138. };
  139. idc.start();
  140. }
  141. #[cfg(all(
  142. feature = "zeroidc",
  143. any(
  144. all(target_os = "linux", target_arch = "x86"),
  145. all(target_os = "linux", target_arch = "x86_64"),
  146. all(target_os = "linux", target_arch = "aarch64"),
  147. target_os = "windows",
  148. target_os = "macos",
  149. )
  150. ))]
  151. #[no_mangle]
  152. pub unsafe extern "C" fn zeroidc_stop(ptr: *mut ZeroIDC) {
  153. let idc = unsafe {
  154. assert!(!ptr.is_null());
  155. &mut *ptr
  156. };
  157. idc.stop();
  158. }
  159. #[cfg(all(
  160. feature = "zeroidc",
  161. any(
  162. all(target_os = "linux", target_arch = "x86"),
  163. all(target_os = "linux", target_arch = "x86_64"),
  164. all(target_os = "linux", target_arch = "aarch64"),
  165. target_os = "windows",
  166. target_os = "macos",
  167. )
  168. ))]
  169. #[no_mangle]
  170. pub unsafe extern "C" fn zeroidc_is_running(ptr: *mut ZeroIDC) -> bool {
  171. let idc = unsafe {
  172. assert!(!ptr.is_null());
  173. &mut *ptr
  174. };
  175. idc.is_running()
  176. }
  177. #[cfg(all(
  178. feature = "zeroidc",
  179. any(
  180. all(target_os = "linux", target_arch = "x86"),
  181. all(target_os = "linux", target_arch = "x86_64"),
  182. all(target_os = "linux", target_arch = "aarch64"),
  183. target_os = "windows",
  184. target_os = "macos",
  185. )
  186. ))]
  187. #[no_mangle]
  188. pub unsafe extern "C" fn zeroidc_get_exp_time(ptr: *mut ZeroIDC) -> u64 {
  189. let id = unsafe {
  190. assert!(!ptr.is_null());
  191. &mut *ptr
  192. };
  193. id.get_exp_time()
  194. }
  195. #[cfg(all(
  196. feature = "zeroidc",
  197. any(
  198. all(target_os = "linux", target_arch = "x86"),
  199. all(target_os = "linux", target_arch = "x86_64"),
  200. all(target_os = "linux", target_arch = "aarch64"),
  201. target_os = "windows",
  202. target_os = "macos",
  203. )
  204. ))]
  205. #[no_mangle]
  206. pub unsafe extern "C" fn zeroidc_set_nonce_and_csrf(
  207. ptr: *mut ZeroIDC,
  208. csrf_token: *const c_char,
  209. nonce: *const c_char,
  210. ) {
  211. let idc = unsafe {
  212. assert!(!ptr.is_null());
  213. &mut *ptr
  214. };
  215. if csrf_token.is_null() {
  216. println!("csrf_token is null");
  217. return;
  218. }
  219. if nonce.is_null() {
  220. println!("nonce is null");
  221. return;
  222. }
  223. let csrf_token = unsafe { CStr::from_ptr(csrf_token) }.to_str().unwrap().to_string();
  224. let nonce = unsafe { CStr::from_ptr(nonce) }.to_str().unwrap().to_string();
  225. idc.set_nonce_and_csrf(csrf_token, nonce);
  226. }
  227. #[cfg(all(
  228. feature = "zeroidc",
  229. any(
  230. all(target_os = "linux", target_arch = "x86"),
  231. all(target_os = "linux", target_arch = "x86_64"),
  232. all(target_os = "linux", target_arch = "aarch64"),
  233. target_os = "windows",
  234. target_os = "macos",
  235. )
  236. ))]
  237. #[no_mangle]
  238. pub unsafe extern "C" fn free_cstr(s: *mut c_char) {
  239. if s.is_null() {
  240. println!("passed a null object");
  241. return;
  242. }
  243. unsafe {
  244. let _ = CString::from_raw(s);
  245. }
  246. }
  247. #[cfg(all(
  248. feature = "zeroidc",
  249. any(
  250. all(target_os = "linux", target_arch = "x86"),
  251. all(target_os = "linux", target_arch = "x86_64"),
  252. all(target_os = "linux", target_arch = "aarch64"),
  253. target_os = "windows",
  254. target_os = "macos",
  255. )
  256. ))]
  257. #[no_mangle]
  258. pub unsafe extern "C" fn zeroidc_get_auth_url(ptr: *mut ZeroIDC) -> *mut c_char {
  259. if ptr.is_null() {
  260. println!("passed a null object");
  261. return std::ptr::null_mut();
  262. }
  263. let idc = unsafe { &mut *ptr };
  264. let s = CString::new(idc.auth_url()).unwrap();
  265. s.into_raw()
  266. }
  267. #[cfg(all(
  268. feature = "zeroidc",
  269. any(
  270. all(target_os = "linux", target_arch = "x86"),
  271. all(target_os = "linux", target_arch = "x86_64"),
  272. all(target_os = "linux", target_arch = "aarch64"),
  273. target_os = "windows",
  274. target_os = "macos",
  275. )
  276. ))]
  277. #[no_mangle]
  278. pub unsafe extern "C" fn zeroidc_token_exchange(idc: *mut ZeroIDC, code: *const c_char) -> *mut c_char {
  279. if idc.is_null() {
  280. println!("idc is null");
  281. return std::ptr::null_mut();
  282. }
  283. if code.is_null() {
  284. println!("code is null");
  285. return std::ptr::null_mut();
  286. }
  287. let idc = unsafe { &mut *idc };
  288. let code = unsafe { CStr::from_ptr(code) }.to_str().unwrap();
  289. let ret = idc.do_token_exchange(code);
  290. match ret {
  291. Ok(ret) => {
  292. #[cfg(debug_assertions)]
  293. {
  294. println!("do_token_exchange ret: {}", ret);
  295. }
  296. let ret = CString::new(ret).unwrap();
  297. ret.into_raw()
  298. }
  299. Err(e) => {
  300. #[cfg(debug_assertions)]
  301. {
  302. println!("do_token_exchange err: {}", e);
  303. }
  304. let errstr = format!("{{\"errorMessage\": \"{}\"}}", e);
  305. let ret = CString::new(errstr).unwrap();
  306. ret.into_raw()
  307. }
  308. }
  309. }
  310. #[no_mangle]
  311. pub unsafe extern "C" fn zeroidc_get_url_param_value(param: *const c_char, path: *const c_char) -> *mut c_char {
  312. if param.is_null() {
  313. println!("param is null");
  314. return std::ptr::null_mut();
  315. }
  316. if path.is_null() {
  317. println!("path is null");
  318. return std::ptr::null_mut();
  319. }
  320. let param = unsafe { CStr::from_ptr(param) }.to_str().unwrap();
  321. let path = unsafe { CStr::from_ptr(path) }.to_str().unwrap();
  322. let url = "http://localhost:9993".to_string() + path;
  323. let url = Url::parse(&url).unwrap();
  324. let pairs = url.query_pairs();
  325. for p in pairs {
  326. if p.0 == param {
  327. let s = CString::new(p.1.into_owned()).unwrap();
  328. return s.into_raw();
  329. }
  330. }
  331. std::ptr::null_mut()
  332. }
  333. #[no_mangle]
  334. pub unsafe extern "C" fn zeroidc_network_id_from_state(state: *const c_char) -> *mut c_char {
  335. if state.is_null() {
  336. println!("state is null");
  337. return std::ptr::null_mut();
  338. }
  339. let state = unsafe { CStr::from_ptr(state) }.to_str().unwrap();
  340. let split = state.split('_');
  341. let split = split.collect::<Vec<&str>>();
  342. if split.len() != 2 {
  343. return std::ptr::null_mut();
  344. }
  345. let s = CString::new(split[1]).unwrap();
  346. s.into_raw()
  347. }
  348. #[cfg(all(
  349. feature = "zeroidc",
  350. any(
  351. all(target_os = "linux", target_arch = "x86"),
  352. all(target_os = "linux", target_arch = "x86_64"),
  353. all(target_os = "linux", target_arch = "aarch64"),
  354. target_os = "windows",
  355. target_os = "macos",
  356. )
  357. ))]
  358. #[no_mangle]
  359. pub unsafe extern "C" fn zeroidc_kick_refresh_thread(idc: *mut ZeroIDC) {
  360. if idc.is_null() {
  361. println!("idc is null");
  362. return;
  363. }
  364. let idc = unsafe { &mut *idc };
  365. idc.kick_refresh_thread();
  366. }
  367. #[cfg(feature = "ztcontroller")]
  368. use crate::smeeclient::NetworkJoinedParams;
  369. #[cfg(feature = "ztcontroller")]
  370. use crate::smeeclient::SmeeClient;
  371. #[cfg(feature = "ztcontroller")]
  372. #[no_mangle]
  373. pub unsafe extern "C" fn smee_client_new(
  374. temporal_url: *const c_char,
  375. namespace: *const c_char,
  376. task_queue: *const c_char,
  377. ) -> *mut SmeeClient {
  378. let url = unsafe {
  379. assert!(!temporal_url.is_null());
  380. CStr::from_ptr(temporal_url).to_str().unwrap()
  381. };
  382. let ns = unsafe {
  383. assert!(!namespace.is_null());
  384. CStr::from_ptr(namespace).to_str().unwrap()
  385. };
  386. let tq = unsafe {
  387. assert!(!task_queue.is_null());
  388. CStr::from_ptr(task_queue).to_str().unwrap()
  389. };
  390. match SmeeClient::new(url, ns, tq) {
  391. Ok(c) => Box::into_raw(Box::new(c)),
  392. Err(e) => {
  393. println!("error creating smee client instance: {}", e);
  394. std::ptr::null_mut()
  395. }
  396. }
  397. }
  398. #[cfg(feature = "ztcontroller")]
  399. #[no_mangle]
  400. pub unsafe extern "C" fn smee_client_delete(ptr: *mut SmeeClient) {
  401. if ptr.is_null() {
  402. return;
  403. }
  404. let smee = unsafe {
  405. assert!(!ptr.is_null());
  406. Box::from_raw(&mut *ptr)
  407. };
  408. drop(smee);
  409. }
  410. #[cfg(feature = "ztcontroller")]
  411. #[no_mangle]
  412. pub unsafe extern "C" fn smee_client_notify_network_joined(
  413. smee_instance: *mut SmeeClient,
  414. network_id: *const c_char,
  415. member_id: *const c_char,
  416. ) -> bool {
  417. let nwid = unsafe {
  418. assert!(!network_id.is_null());
  419. CStr::from_ptr(network_id).to_str().unwrap()
  420. };
  421. let mem_id = unsafe {
  422. assert!(!member_id.is_null());
  423. CStr::from_ptr(member_id).to_str().unwrap()
  424. };
  425. let smee = unsafe {
  426. assert!(!smee_instance.is_null());
  427. &mut *smee_instance
  428. };
  429. let params = NetworkJoinedParams::new(nwid, mem_id);
  430. match smee.notify_network_joined(params) {
  431. Ok(()) => true,
  432. Err(e) => {
  433. println!("error notifying network joined: {0}", e);
  434. false
  435. }
  436. }
  437. }