syslog_rs/sync/
syslog_sync_internal.rs1use std::io::Error;
18
19use instance_copy_on_write::{ICoW, ICoWRead};
20
21use crate::formatters::{SyslogFormatted, SyslogFormatter};
22use crate::portable;
23use crate::common::*;
24use crate::error::{SyRes, SyslogError};
25use crate::SyslogDestination;
26
27use super::socket::*;
28
29#[cfg(target_family = "unix")]
30use nix::libc;
31
32#[derive(Debug, Clone)]
33pub(crate) struct LogItems
34{
35 pub(crate) logtag: String,
37
38 pub(crate) logpid: String,
40
41 pub(crate) logmask: i32,
43
44 pub(crate) logstat: LogStat,
45
46 pub(crate) facility: LogFacility,
48}
49
50impl LogItems
51{
52 #[inline]
53 pub
54 fn new(ident: Option<&str>, logmask: i32, logstat: LogStat, facility: LogFacility) -> Self
55 {
56 let mut log_inst =
57 Self
58 {
59 logtag: String::new(),
60 logpid: portable::get_pid().to_string(),
61 logmask: logmask,
62 logstat: logstat,
63 facility: LogFacility::empty(),
64 };
65
66 log_inst.set_log_facility(facility);
67 log_inst.set_identity(ident);
68
69 return log_inst;
70 }
71
72 pub(crate)
73 fn set_log_facility(&mut self, facility: LogFacility)
74 {
75 let log_facility =
76 if facility.is_empty() == false &&
77 (facility & !LogMask::LOG_FACMASK).is_empty() == true
78 {
79 facility
80 }
81 else
82 {
83 LogFacility::LOG_USER
85 };
86
87 self.facility = log_facility;
88
89 return;
90 }
91
92 pub(crate)
93 fn set_identity(&mut self, ident: Option<&str>)
94 {
95 let logtag =
96 match ident
97 {
98 Some(r) =>
99 truncate_n(r, RFC_MAX_APP_NAME).to_string(),
100 None =>
101 truncate_n(
102 portable::p_getprogname()
103 .unwrap_or("notavail".to_string())
104 .as_str(),
105 RFC_MAX_APP_NAME
106 )
107 .to_string()
108 };
109
110 self.logtag = logtag;
111
112 return;
113 }
114
115 #[inline]
116 pub
117 fn get_progname(&self) -> &str
118 {
119 return &self.logtag;
120 }
121
122 #[inline]
123 pub
124 fn get_pid(&self) -> &str
125 {
126 return &self.logtag;
127 }
128
129 #[inline]
130 fn is_logmasked(&self, pri: Priority) -> bool
131 {
132 return ((1 << (pri & LogMask::LOG_PRIMASK)) & self.logmask) == 0;
133 }
134
135 pub(crate)
136 fn set_logmask(&mut self, logmask: i32) -> i32
137 {
138 let oldmask = self.logmask;
139
140 if logmask != 0
141 {
142 self.logmask = logmask;
143 }
144
145 return oldmask;
146 }
147
148 pub(crate)
149 fn vsyslog1_msg<F, D>(&self, mut pri: Priority, fmt: &F) -> Option<(SyslogFormatted, LogStat)>
150 where F: SyslogFormatter, D: SyslogDestination
151 {
152 if let Err(e) = pri.check_invalid_bits()
154 {
155 self.logstat.send_to_stderr(&e.to_string());
156 }
157
158 if self.is_logmasked(pri) == true
160 {
161 return None;
162 }
163
164 if (pri.bits() & LOG_FACMASK) == 0
166 {
167 pri.set_facility(self.facility);
168 }
169
170 let msg_pid =
172 if self.logstat.intersects(LogStat::LOG_PID) == true
173 {
174 Some(self.logpid.as_str())
175 }
176 else
177 {
178 None
179 };
180
181 let msg_formatted =
183 fmt.vsyslog1_format(D::SocketTap::get_max_msg_size(), pri, &self.logtag, msg_pid);
184
185 self.logstat.send_to_stderr(msg_formatted.get_stderr_output());
187
188 return Some((msg_formatted, self.logstat));
189 }
190}
191
192#[derive(Debug)]
193pub(crate) struct SyslogSocket<D: SyslogDestination>
194{
195 stream: ICoW<D::SocketTap>
196}
197
198impl<D: SyslogDestination> SyslogSocket<D>
199{
200 pub(crate)
201 fn new(logstat: LogStat, net_tap_prov: D) -> SyRes<Self>
202 {
203 let mut sock =
204 D::SocketTap::new(net_tap_prov)?;
205
206 if logstat.contains(LogStat::LOG_NDELAY) == true
207 {
208 sock.connectlog()?;
209 }
210
211 return Ok(
212 Self{ stream: ICoW::new(sock) }
213 );
214 }
215
216 #[inline]
217 pub(crate)
218 fn update_tap_data(&self, tap_data: D) -> SyRes<()>
219 {
220
221 let mut lock =
222 self
223 .stream
224 .clone_copy_exclusivly();
225
226 lock.update_tap_data(tap_data);
229
230 lock.connectlog()?;
231
232 lock.commit();
233
234 return Ok(());
235 }
236
237 #[inline]
238 pub(crate)
239 fn reconnectlog(&self) -> SyRes<()>
240 {
241 let mut lock =
242 self
243 .stream
244 .clone_copy_exclusivly();
245
246 lock.connectlog()?;
248
249 lock.commit();
250
251 return Ok(());
252 }
253
254 #[inline]
255 pub(crate)
256 fn connectlog(&self) -> SyRes<()>
257 {
258 let mut lock =
259 self
260 .stream
261 .clone_copy_exclusivly();
262
263 lock.connectlog()?;
264
265 lock.commit();
266
267 return Ok(());
268 }
269
270 #[inline]
273 pub(crate)
274 fn disconnectlog(&self) -> SyRes<()>
275 {
276 let lock =
277 self
278 .stream
279 .clone_copy_exclusivly();
280
281 lock.commit();
282
283 return Ok(());
284 }
285
286 #[cfg(target_family = "unix")]
288 fn handle_error<'h>(&'h self, stream: ICoWRead<'h, <D as SyslogDestination>::SocketTap>,
289 e: Error) -> Result<ICoWRead<'h, D::SocketTap>, SyslogError>
290 {
291 use std::io::ErrorKind;
292 use std::thread::sleep;
293 use std::time::Duration;
294
295 if e.kind() == ErrorKind::NotConnected
297 {
298 match self.stream.clone_copy_exclus_or_read()
299 {
300 Ok(mut lock) =>
301 {
302 lock.connectlog()?;
303
304 lock.commit();
305
306 return Ok(self.stream.read());
307 },
308 Err(read) =>
309 {
310 return Ok(read);
311 }
312 }
313 }
314 else
315 {
316 if D::DEST_TYPE.is_network() == false
317 {
318 if let Some(libc::ENOBUFS) = e.raw_os_error()
319 {
320 if stream.get_type().is_priv() == true
322 {
323 use nix::errno::Errno;
324
325 use crate::throw_error_errno;
326
327 throw_error_errno!(Errno::ENOBUFS, "Not enough space in priv socket.");
328 }
329
330 sleep(Duration::from_micros(1));
331
332 return Ok(stream);
333 }
334 else
335 {
336 match self.stream.clone_copy_exclus_or_read()
338 {
339 Ok(mut lock) =>
340 {
341 lock.connectlog()?;
342
343 lock.commit();
344
345 return Ok(self.stream.read());
346 },
347 Err(read) =>
348 {
349 return Ok(read);
350 }
351 }
352
353 }
355 }
356 else
357 {
358 match self.stream.clone_copy_exclus_or_read()
359 {
360 Ok(mut lock) =>
361 {
362 lock.connectlog()?;
363
364 lock.commit();
365
366 return Ok(self.stream.read());
367 },
368 Err(read) =>
369 {
370 return Ok(read);
371 }
372 }
373 }
374 }
375 }
376
377 #[cfg(target_family = "windows")]
379 fn handle_error<'h>(&'h self, _stream: ICoWRead<'h, <D as SyslogDestination>::SocketTap>,
380 e: Error) -> Result<ICoWRead<'h, D::SocketTap>, SyslogError>
381 {
382 use crate::DestinationType;
383 use crate::error::SyslogErrCode;
384
385 if D::DEST_TYPE == DestinationType::Local
386 {
387 let Ok(werr) = e.downcast::<windows::core::Error>()
389 else
390 {
391
392
393 return Err(
394 SyslogError::new(SyslogErrCode::InternalError,
395 "error downcast failed".into())
396 );
397 };
398
399 return Err(
400 SyslogError::new(
401 SyslogErrCode::InternalError,
402 werr.message()
403 )
404 );
405 }
406 else if D::DEST_TYPE == DestinationType::Network
407 {
408 match self.stream.clone_copy_exclus_or_read()
409 {
410 Ok(mut lock) =>
411 {
412 lock.connectlog()?;
413
414 lock.commit();
415
416 return Ok(self.stream.read());
417 },
418 Err(read) =>
419 {
420 return Ok(read);
421 }
422 }
423 }
424 else
425 {
426 return Err(
427 SyslogError::new(
428 SyslogErrCode::InternalError,
429 format!("IO error: {}", e)
430 )
431 );
432 }
433
434 }
435
436
437 pub(crate)
446 fn vsyslog1(&self, logstat: LogStat, mut msg_formatted: SyslogFormatted)
447 {
448 let fullmsg = msg_formatted.get_full_msg();
449
450 let mut stream = self.stream.read();
451
452 loop
453 {
454 match stream.send(fullmsg.as_bytes())
455 {
456 Ok(_) =>
457 return,
458 Err(e) =>
459 {
460 match self.handle_error(stream, e)
461 {
462 Ok(read) =>
463 {
464 stream = read;
465
466 continue;
467 },
468 Err(e) =>
469 {
470 logstat.send_to_stderr(&format!("connectlog() failed with {}", e));
471 break;
472 }
473 }
474 }
475 }
476 }
477
478
479 let _ = logstat.send_to_syscons(msg_formatted.get_stderr_output());
483
484 return;
485 }
486
487}
488
489#[cfg(any(feature = "build_with_thread_local", feature = "build_with_queue"))]
490pub mod lockless
491{
492 use std::io::ErrorKind;
493 use std::thread::sleep;
494 use std::time::Duration;
495
496 use super::*;
497
498 #[derive(Debug)]
499 pub(crate) struct SyslogSocketLockless<D: SyslogDestination>
500 {
501 stream: D::SocketTap
502 }
503
504 impl<D: SyslogDestination> SyslogSocketLockless<D>
505 {
506 pub(crate)
507 fn new(logstat: LogStat, net_tap_prov: D) -> SyRes<Self>
508 {
509 let mut sock =
510 D::SocketTap::new(net_tap_prov)?;
511
512 if logstat.contains(LogStat::LOG_NDELAY) == true
513 {
514 sock.connectlog()?;
515 }
516
517 return Ok(
518 Self{ stream: sock }
519 );
520 }
521
522 #[inline]
523 pub(crate)
524 fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
525 {
526 self.stream.disconnectlog()?;
527 self.stream.update_tap_data(tap_data);
528
529 return self.stream.connectlog();
530 }
531
532 #[inline]
533 pub(crate)
534 fn reconnectlog(&mut self) -> SyRes<()>
535 {
536 self.stream.disconnectlog()?;
537 self.stream.connectlog()?;
538
539 return Ok(());
540 }
541
542 #[inline]
543 pub(crate)
544 fn connectlog(&mut self) -> SyRes<()>
545 {
546 return self.stream.connectlog();
547 }
548
549 #[inline]
552 pub(crate)
553 fn disconnectlog(&mut self) -> SyRes<()>
554 {
555 return self.stream.disconnectlog();
556 }
557
558
559
560 pub(crate)
569 fn vsyslog1(&mut self, logstat: LogStat, mut msg_formatted: SyslogFormatted)
570 {
571 if self.stream.is_connected() == false
572 {
573 if let Err(e) = self.stream.connectlog()
574 {
575 logstat.send_to_stderr(&e.into_inner());
576 }
577 }
578
579 let fullmsg = msg_formatted.get_full_msg();
580
581 let mut repeated = false;
582 loop
583 {
584 match self.stream.send(fullmsg.as_bytes())
585 {
586 Ok(_) =>
587 return,
588 Err(ref e) if e.kind() == ErrorKind::NotConnected =>
589 {
590 break;
591 },
592 Err(ref e) if e.kind() == ErrorKind::Deadlock =>
594 {
595 logstat.send_to_stderr(&e.to_string());
596 break;
597 },
598 Err(err) =>
599 {
600 if D::DEST_TYPE.is_network() == false
601 {
602 #[cfg(target_family = "unix")]
603 {
604 if let Some(libc::ENOBUFS) = err.raw_os_error()
605 {
606 if self.stream.get_type().is_priv() == true
608 {
609 break;
610 }
611
612 sleep(Duration::from_micros(1));
613 }
614 else
615 {
616 let _ = self.stream.disconnectlog();
618 if let Err(e) = self.stream.connectlog()
619 {
620 logstat.send_to_stderr(&e.into_inner());
621 break;
622 }
623 }
624 }
625
626 #[cfg(target_family = "windows")]
627 {
628 let Ok(werr) = err.downcast::<windows::core::Error>()
629 else
630 {
631 logstat.send_to_stderr("error downcast failed");
632 break;
633 };
634
635 logstat.send_to_stderr(&werr.message());
636 break;
637 }
638
639 }
641 else
642 {
643 if repeated == false
644 {
645 repeated = true;
646
647 let _ = self.stream.disconnectlog();
648 if let Err(e) = self.stream.connectlog()
649 {
650 logstat.send_to_stderr(&e.into_inner());
651 break;
652 }
653 }
654 else
655 {
656 logstat.send_to_stderr("syslog: can not send to remote server");
657 break;
658 }
659 }
660
661 }
662 }
663 }
664
665
666 let _ = logstat.send_to_syscons(msg_formatted.get_stderr_output());
670
671 return;
672 }
673
674 }
675}
676
677#[cfg(any(feature = "build_with_thread_local", feature = "build_with_queue"))]
678pub use self::lockless::*;
679
680
681
682#[cfg(test)]
683mod tests
684{
685 use crate::LOG_MASK;
686
687 use super::*;
688
689 #[test]
690 fn test_log_cons()
691 {
692
693
694 let msg = "header msg message payload";
697
698 let lsts = LogStat::LOG_CONS;
699
700 lsts.send_to_syscons(msg);
701
702 return;
703 }
704
705 #[test]
706 fn test_bit_operations()
707 {
708
709 let correct =
710 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
711
712 assert_eq!(correct.facility, LogFacility::LOG_DAEMON);
713 assert_eq!((correct.facility & !LogFacility::LOG_DAEMON), LogFacility::empty());
714 }
715
716 #[test]
717 fn test_bit_operations2()
718 {
719
720 let mut pri = Priority::LOG_ALERT;
721
722 let res = pri.check_invalid_bits();
723
724 assert_eq!(res.is_ok(), true);
725 assert_eq!(pri.bits(), Priority::LOG_ALERT.bits());
726 }
727
728 #[test]
729 fn test_set_priority()
730 {
731 let mut correct =
732 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
733
734 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
735
736 assert_eq!(ret, 0xff);
737
738 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
739
740 assert_eq!(ret, LOG_MASK!(Priority::LOG_ERR));
741
742 let ret = correct.is_logmasked(Priority::LOG_WARNING);
743 assert_eq!(ret, true);
744
745 let ret = correct.is_logmasked(Priority::LOG_ERR);
746 assert_eq!(ret, false);
747
748 let ret = correct.is_logmasked(Priority::LOG_CRIT);
749 assert_eq!(ret, true);
750 }
751}
752