1#[macro_export]
8macro_rules! create_dynamic_library {
9 ($t:ty) => {
10 macro_rules! debug_assert_null_or_str {
11 ($ptr:expr, $l:literal) => {
12 unsafe {
13 debug_assert!(!$ptr.is_null(), "ptr is null!");
14 let c_str = std::ffi::CStr::from_ptr($ptr);
15 c_str.to_str().expect($l)
16 }
17 };
18 }
19
20 macro_rules! debug_assert_null_or_slice {
21 ($data:expr, $datalen:expr, $l:literal) => {
22 unsafe {
23 let event_data = $data as *const u8;
24 if event_data.is_null() {
25 PAYLOAD_NULL
26 } else {
27 debug_assert!(!event_data.is_null(), $l);
28 std::slice::from_raw_parts(event_data, $datalen as usize)
29 }
30 }
31 };
32 }
33
34 use mosquitto_dev::*;
35 use std::ffi::CString;
36 use std::os::raw::c_int;
37 use std::os::raw::c_void;
38
39 const PAYLOAD_NULL: &[u8] = &[];
40
41 fn __assert_sync()
42 where
43 $t: MosquittoPlugin,
44 {
45 }
46
47 struct InternalUserData {
51 identifier: *mut c_void,
52 external_user_data: $t,
53 }
54
55 #[no_mangle]
56 pub extern "C" fn mosquitto_plugin_version() -> isize {
57 mosquitto_dev::MOSQ_PLUGIN_VERSION as isize
58 }
59
60 #[no_mangle]
64 extern "C" fn on_reload_trampoline(
65 _event: c_int,
66 event_data: *mut c_void,
67 user_data: *mut c_void,
68 ) -> c_int {
69 debug_assert!(
70 !event_data.is_null(),
71 "on_reload_trampoline event_data is null"
72 );
73 debug_assert!(
74 !user_data.is_null(),
75 "on_reload_trampoline user_data is null"
76 );
77 let user_data: &mut InternalUserData =
78 unsafe { &mut *(user_data as *mut InternalUserData) };
79 let event_data: &mut mosquitto_evt_reload =
80 unsafe { &mut *(event_data as *mut mosquitto_evt_reload) };
81 let opts = __from_ptr_and_size(event_data.options, event_data.option_count as _);
82 user_data.external_user_data.on_reload(opts);
83 0
84 }
85
86 #[no_mangle]
87 extern "C" fn on_acl_check_trampoline(
88 _event: c_int,
89 event_data: *mut c_void,
90 user_data: *mut c_void,
91 ) -> c_int {
92 debug_assert!(
93 !event_data.is_null(),
94 "on_acl_check_trampoline event_data is null"
95 );
96 debug_assert!(
97 !user_data.is_null(),
98 "on_acl_check_trampoline user_data is null"
99 );
100 let user_data: &mut InternalUserData =
101 unsafe { &mut *(user_data as *mut InternalUserData) };
102 let event_data: &mut mosquitto_evt_acl_check =
103 unsafe { &mut *(event_data as *mut mosquitto_evt_acl_check) };
104 let access_level: AccessLevel = event_data.access.into();
105 let access_level = if let Some(level) = access_level.into() {
106 level
107 } else {
108 mosquitto_warn!("Unexpected access level for acl check. {:?}", access_level);
109 return Error::Unknown.into();
110 };
111
112 let topic: &str = debug_assert_null_or_str!(
113 event_data.topic,
114 "failed to create topic str on acl check trampoline"
115 );
116
117 let payload: &[u8] = debug_assert_null_or_slice!(
118 event_data.payload,
119 event_data.payloadlen,
120 "acl_check_trampoline payload is null"
121 );
122
123 let msg = MosquittoMessage {
124 topic,
125 payload,
126 qos: event_data.qos.into(),
127 retain: event_data.retain,
128 };
129 match user_data.external_user_data.acl_check(
130 &MosquittoClient {
131 client: event_data.client,
132 },
133 access_level,
134 msg,
135 ) {
136 Ok(s) => s.into(),
137 Err(e) => e.into(),
138 }
139 }
140
141 #[no_mangle]
142 extern "C" fn on_basic_auth_trampoline(
143 _event: c_int,
144 event_data: *mut c_void,
145 user_data: *mut c_void,
146 ) -> c_int {
147 debug_assert!(
148 !event_data.is_null(),
149 "on_basic_auth_trampoline event_data is null"
150 );
151 debug_assert!(
152 !user_data.is_null(),
153 "on_basic_auth_trampoline user_data is null"
154 );
155 let user_data: &mut InternalUserData =
156 unsafe { &mut *(user_data as *mut InternalUserData) };
157 let event_data: &mut mosquitto_evt_basic_auth =
158 unsafe { &mut *(event_data as *mut mosquitto_evt_basic_auth) };
159
160 let username: Option<&str> = unsafe {
161 if event_data.username.is_null() {
162 None
163 } else {
164 let c_str = std::ffi::CStr::from_ptr(event_data.username);
165 Some(c_str.to_str().expect(
166 "basic auth trampoline failed to create username &str from CStr pointer",
167 ))
168 }
169 };
170 let password: Option<&str> = unsafe {
171 if event_data.password.is_null() {
172 None
173 } else {
174 let c_str = std::ffi::CStr::from_ptr(event_data.password);
175 Some(c_str.to_str().expect(
176 "basic auth trampoline failed to create password &str from CStr pointer",
177 ))
178 }
179 };
180
181 debug_assert!(
182 !event_data.client.is_null(),
183 "no client in basic auth trampoline"
184 );
185
186 match user_data.external_user_data.username_password(
187 &MosquittoClient {
188 client: event_data.client,
189 },
190 username,
191 password,
192 ) {
193 Ok(r) => r.into(),
194 Err(e) => e.into(),
195 }
196 }
197
198 #[no_mangle]
199 extern "C" fn on_auth(
200 event: c_int,
201 event_data: *mut c_void,
202 user_data: *mut c_void,
203 ) -> c_int {
204 debug_assert!(!event_data.is_null(), "on_auth event_data is null");
205 debug_assert!(!user_data.is_null(), "on_auth user_data is null");
206 let user_data: &mut InternalUserData =
207 unsafe { &mut *(user_data as *mut InternalUserData) };
208 let event_data: &mut mosquitto_evt_extended_auth =
209 unsafe { &mut *(event_data as *mut mosquitto_evt_extended_auth) };
210
211 let method = (!event_data.auth_method.is_null()).then(|| unsafe {
212 let c_str = std::ffi::CStr::from_ptr(event_data.auth_method);
213 c_str.to_str().expect(
214 "auth start trampoline failed to create auth method &str from CStr pointer",
215 )
216 });
217
218 let data_in = (!event_data.data_in.is_null()).then(|| unsafe {
219 std::slice::from_raw_parts(
220 event_data.data_in as *const u8,
221 event_data.data_in_len as usize,
222 )
223 });
224
225 let result = if event == MosquittoPluginEvent::MosqEvtExtAuthStart as c_int {
226 user_data.external_user_data.on_auth_start(
227 &MosquittoClient {
228 client: event_data.client,
229 },
230 method,
231 data_in,
232 )
233 } else if event == MosquittoPluginEvent::MosqEvtExtAuthContinue as c_int {
234 user_data.external_user_data.on_auth_continue(
235 &MosquittoClient {
236 client: event_data.client,
237 },
238 method,
239 data_in,
240 )
241 } else {
242 unreachable!("invalid event type");
243 };
244
245 match result {
246 Ok(r) => r.into(),
247 Err(Error::AuthContinue(data_out)) => {
248 debug_assert!(data_out.len() <= u16::MAX as usize);
249 event_data.data_out_len = data_out.len() as u16;
250 event_data.data_out = data_out.as_ptr() as _;
251 std::mem::forget(data_out);
252 Error::AuthContinue(Vec::with_capacity(0)).into()
253 }
254 Err(e) => e.into(),
255 }
256 }
257
258 #[no_mangle]
259 extern "C" fn on_control_trampoline(
260 _event: c_int,
261 event_data: *mut c_void,
262 user_data: *mut c_void,
263 ) -> c_int {
264 debug_assert!(
265 !event_data.is_null(),
266 "on_control_trampoline event_data is null"
267 );
268 debug_assert!(
269 !user_data.is_null(),
270 "on_control_trampoline user_data is null"
271 );
272 let user_data: &mut InternalUserData =
273 unsafe { &mut *(user_data as *mut InternalUserData) };
274 let event_data: &mut mosquitto_evt_control =
275 unsafe { &mut *(event_data as *mut mosquitto_evt_control) };
276
277 let topic: &str = debug_assert_null_or_str!(
278 event_data.topic,
279 "control trampoline failed to create topic &str from CStr pointer"
280 );
281
282 let payload: &[u8] = debug_assert_null_or_slice!(
283 event_data.payload,
284 event_data.payloadlen,
285 "on_control_trampoline payload is null"
286 );
287
288 let msg = MosquittoMessage {
289 topic,
290 payload,
291 qos: event_data.qos.into(),
292 retain: event_data.retain,
293 };
294
295 user_data.external_user_data.on_control(
296 &MosquittoClient {
297 client: event_data.client,
298 },
299 msg,
300 );
301 0
302 }
303
304 #[no_mangle]
305 extern "C" fn on_message_trampoline(
306 _event: c_int,
307 event_data: *mut c_void,
308 user_data: *mut c_void,
309 ) -> c_int {
310 debug_assert!(
311 !event_data.is_null(),
312 "on_message_trampoline event_data is null"
313 );
314 debug_assert!(
315 !user_data.is_null(),
316 "on_message_trampoline user_data is null"
317 );
318 let user_data: &mut InternalUserData =
319 unsafe { &mut *(user_data as *mut InternalUserData) };
320 let event_data: &mut mosquitto_evt_message =
321 unsafe { &mut *(event_data as *mut mosquitto_evt_message) };
322
323 let topic: &str = debug_assert_null_or_str!(
324 event_data.topic,
325 "message trampoline failed to create topic &str from CStr pointer"
326 );
327
328 let payload: &[u8] = debug_assert_null_or_slice!(
329 event_data.payload,
330 event_data.payloadlen,
331 "on_message_trampoline_is_null"
332 );
333
334 let msg = MosquittoMessage {
335 topic,
336 payload,
337 qos: event_data.qos.into(),
338 retain: event_data.retain,
339 };
340
341 user_data.external_user_data.on_message(
342 &MosquittoClient {
343 client: event_data.client,
344 },
345 msg,
346 );
347 0
348 }
349
350 #[no_mangle]
351 extern "C" fn on_psk_key_trampoline(
352 _event: c_int,
353 event_data: *mut c_void,
354 user_data: *mut c_void,
355 ) -> c_int {
356 debug_assert!(
357 !event_data.is_null(),
358 "on_psk_key_trampoline event_data is null"
359 );
360 debug_assert!(
361 !user_data.is_null(),
362 "on_psk_key_trampoline user_data is null"
363 );
364 let user_data: &mut InternalUserData =
365 unsafe { &mut *(user_data as *mut InternalUserData) };
366 let event_data: &mut mosquitto_evt_psk_key =
367 unsafe { &mut *(event_data as *mut mosquitto_evt_psk_key) };
368
369 let hint: &str = debug_assert_null_or_str!(
370 event_data.hint,
371 "psk key trampoline failed to create hint &str from CStr pointer"
372 );
373
374 let identity: &str = debug_assert_null_or_str!(
375 event_data.identity,
376 "psk key trampoline failed to create identity &str from CStr pointer"
377 );
378
379 let key: &str = debug_assert_null_or_str!(
380 event_data.key,
381 "psk key trampoline failed to create key &str from CStr pointer"
382 );
383
384 user_data.external_user_data.on_psk(
385 &MosquittoClient {
386 client: event_data.client,
387 },
388 hint,
389 identity,
390 key,
391 event_data.max_key_len as i32,
392 )
393 }
394
395 #[no_mangle]
396 extern "C" fn on_tick_trampoline(
397 _event: c_int,
398 event_data: *mut c_void,
399 user_data: *mut c_void,
400 ) -> c_int {
401 debug_assert!(
402 !event_data.is_null(),
403 "on_tick_trampoline event_data is null"
404 );
405 debug_assert!(!user_data.is_null(), "on_tick_trampoline user_data is null");
406 let user_data: &mut InternalUserData =
407 unsafe { &mut *(user_data as *mut InternalUserData) };
408 let event_data: &mut mosquitto_evt_tick =
409 unsafe { &mut *(event_data as *mut mosquitto_evt_tick) };
410
411 user_data.external_user_data.on_tick(
412 event_data.now_ns as i64,
413 event_data.next_ns as i64,
414 event_data.now_s as i32,
415 event_data.next_s as i32,
416 );
417 0
418 }
419
420 #[no_mangle]
421 extern "C" fn on_disconnect_trampoline(
422 _event: c_int,
423 event_data: *mut c_void,
424 user_data: *mut c_void,
425 ) -> c_int {
426 debug_assert!(
427 !event_data.is_null(),
428 "on disconnect_trampoline event_data is null"
429 );
430 debug_assert!(
431 !user_data.is_null(),
432 "on disconnect_trampoline user_data is null"
433 );
434 let user_data: &mut InternalUserData = unsafe {
435 &mut *(user_data as *mut InternalUserData)
437 };
438
439 let event_data: &mut mosquitto_evt_disconnect =
440 unsafe { &mut *(event_data as *mut mosquitto_evt_disconnect) };
441
442 let client = MosquittoClient {
443 client: event_data.client,
444 };
445
446 user_data
447 .external_user_data
448 .on_disconnect(&client, event_data.reason);
449
450 0
451 }
452
453 #[no_mangle]
454 pub extern "C" fn mosquitto_plugin_init(
455 identifier: *mut c_void,
456 user_data: *mut *mut c_void, opts: *mut mosquitto_opt,
458 opt_count: c_int,
459 ) -> c_int {
460 let opts = __from_ptr_and_size(opts, opt_count as _);
461 mosquitto_debug!("mosquitto_plugin_init {:?}", opts);
462
463 let instance: $t = <$t>::init(opts);
464 let instance = instance;
465 mosquitto_debug!("external_user_data addr {:?}", instance);
466 let internal_user_data = InternalUserData {
467 identifier,
468 external_user_data: instance,
469 };
470 let internal_user_data = Box::new(internal_user_data);
471 let instance_rawptr: *mut InternalUserData = Box::into_raw(internal_user_data);
472
473 unsafe {
474 *user_data = instance_rawptr as _;
475 }
476
477 unsafe {
478 mosquitto_callback_register(
479 identifier as _,
480 MosquittoPluginEvent::MosqEvtReload as _,
481 Some(on_reload_trampoline),
482 std::ptr::null(),
483 instance_rawptr as _,
484 );
485
486 mosquitto_callback_register(
487 identifier as _,
488 MosquittoPluginEvent::MosqEvtAclCheck as _,
489 Some(on_acl_check_trampoline),
490 std::ptr::null(),
491 instance_rawptr as _,
492 );
493
494 mosquitto_callback_register(
495 identifier as _,
496 MosquittoPluginEvent::MosqEvtBasicAuth as _,
497 Some(on_basic_auth_trampoline),
498 std::ptr::null(),
499 instance_rawptr as _,
500 );
501
502 mosquitto_callback_register(
503 identifier as _,
504 MosquittoPluginEvent::MosqEvtExtAuthStart as _,
505 Some(on_auth),
506 std::ptr::null(),
507 instance_rawptr as _,
508 );
509
510 mosquitto_callback_register(
511 identifier as _,
512 MosquittoPluginEvent::MosqEvtExtAuthContinue as _,
513 Some(on_auth),
514 std::ptr::null(),
515 instance_rawptr as _,
516 );
517
518 let event_data = "$CONTROL";
519 let cstr = &std::ffi::CString::new(event_data).unwrap();
520 let bytes = cstr.as_bytes_with_nul();
521 let topic = bytes.as_ptr() as *const c_void;
522 mosquitto_callback_register(
526 identifier as _,
527 MosquittoPluginEvent::MosqEvtControl as _,
528 Some(on_control_trampoline),
529 topic,
530 instance_rawptr as _,
531 );
532
533 let res = mosquitto_callback_register(
534 identifier as _,
535 MosquittoPluginEvent::MosqEvtMessage as _,
536 Some(on_message_trampoline),
537 std::ptr::null(),
538 instance_rawptr as _,
539 );
540
541 mosquitto_callback_register(
542 identifier as _,
543 MosquittoPluginEvent::MosqEvtPskKey as _,
544 Some(on_psk_key_trampoline),
545 std::ptr::null(),
546 instance_rawptr as _,
547 );
548
549 mosquitto_callback_register(
550 identifier as _,
551 MosquittoPluginEvent::MosqEvtTick as _,
552 Some(on_tick_trampoline),
553 std::ptr::null(),
554 instance_rawptr as _,
555 );
556
557 let res = mosquitto_callback_register(
558 identifier as _,
559 MosquittoPluginEvent::MosqEvtDisconnect as _,
560 Some(on_disconnect_trampoline),
561 std::ptr::null(),
562 instance_rawptr as _,
563 );
564 }
565
566 Success.into()
567 }
568
569 #[no_mangle]
570 extern "C" fn mosquitto_plugin_cleanup(
571 user_data: *mut c_void,
572 opts: *mut mosquitto_opt,
573 opt_count: c_int,
574 ) -> c_int {
575 let opts = __from_ptr_and_size(opts, opt_count as _);
576 let user_data: &mut InternalUserData =
577 unsafe { &mut *(user_data as *mut InternalUserData) };
578
579 unsafe {
580 mosquitto_callback_unregister(
581 user_data.identifier as _,
582 MosquittoPluginEvent::MosqEvtDisconnect as _,
583 Some(on_disconnect_trampoline),
584 std::ptr::null(),
585 );
586 }
587 if !user_data.identifier.is_null() {
588 let identifier = unsafe {
589 let c_str = std::ffi::CStr::from_ptr(user_data.identifier as _);
590 c_str
591 .to_str()
592 .expect("plugin identifier is null at cleanup")
593 };
594 mosquitto_debug!("cleaning up plugin: {}", identifier);
595 }
596 drop(unsafe { Box::from_raw(user_data as *mut InternalUserData) });
597
598 Success.into()
599 }
600 };
601}