syslog_rs/sync/
syslog_sync_internal.rs1use std::io::{Error};
18
19use crate::formatters::{SyslogFormatted, SyslogFormatter};
20use crate::portable;
21use crate::common::*;
22use crate::error::{SyRes, SyslogError};
23use crate::SyslogDestination;
24
25use super::socket::*;
26
27#[cfg(target_family = "unix")]
28use nix::libc;
29
30#[derive(Debug, Clone)]
31pub(crate) struct LogItems
32{
33 pub(crate) logtag: String,
35
36 pub(crate) logpid: String,
38
39 pub(crate) logmask: i32,
41
42 pub(crate) logstat: LogStat,
43
44 pub(crate) facility: LogFacility,
46}
47
48impl LogItems
49{
50 #[inline]
51 pub
52 fn new(ident: Option<&str>, logmask: i32, logstat: LogStat, facility: LogFacility) -> Self
53 {
54 let mut log_inst =
55 Self
56 {
57 logtag: String::new(),
58 logpid: portable::get_pid().to_string(),
59 logmask: logmask,
60 logstat: logstat,
61 facility: LogFacility::empty(),
62 };
63
64 log_inst.set_log_facility(facility);
65 log_inst.set_identity(ident);
66
67 return log_inst;
68 }
69
70 pub(crate)
71 fn set_log_facility(&mut self, facility: LogFacility)
72 {
73 let log_facility =
74 if facility.is_empty() == false &&
75 (facility & !LogMask::LOG_FACMASK).is_empty() == true
76 {
77 facility
78 }
79 else
80 {
81 LogFacility::LOG_USER
83 };
84
85 self.facility = log_facility;
86
87 return;
88 }
89
90 pub(crate)
91 fn set_identity(&mut self, ident: Option<&str>)
92 {
93 let logtag =
94 match ident
95 {
96 Some(r) =>
97 truncate_n(r, RFC_MAX_APP_NAME).to_string(),
98 None =>
99 truncate_n(
100 portable::p_getprogname()
101 .unwrap_or("notavail".to_string())
102 .as_str(),
103 RFC_MAX_APP_NAME
104 )
105 .to_string()
106 };
107
108 self.logtag = logtag;
109
110 return;
111 }
112
113 #[inline]
114 pub
115 fn get_progname(&self) -> &str
116 {
117 return &self.logtag;
118 }
119
120 #[inline]
121 pub
122 fn get_pid(&self) -> &str
123 {
124 return &self.logtag;
125 }
126
127 #[inline]
128 fn is_logmasked(&self, pri: Priority) -> bool
129 {
130 return ((1 << (pri & LogMask::LOG_PRIMASK)) & self.logmask) == 0;
131 }
132
133 pub(crate)
134 fn set_logmask(&mut self, logmask: i32) -> i32
135 {
136 let oldmask = self.logmask;
137
138 if logmask != 0
139 {
140 self.logmask = logmask;
141 }
142
143 return oldmask;
144 }
145
146 pub(crate)
147 fn vsyslog1_msg<F, D>(&self, pri: Priority, fmt: &F) -> Option<(SyslogFormatted, LogStat)>
148 where F: SyslogFormatter, D: SyslogDestination
149 {
150 if self.is_logmasked(pri) == true
160 {
161 return None;
162 }
163
164 let pri_fac = SyslogMsgPriFac::set_facility(pri, self.facility);
166
167 let msg_pid =
176 if self.logstat.intersects(LogStat::LOG_PID) == true
177 {
178 Some(self.logpid.as_str())
179 }
180 else
181 {
182 None
183 };
184
185 let msg_formatted =
187 fmt.vsyslog1_format(D::SocketTap::get_max_msg_size(), pri_fac, &self.logtag, msg_pid);
188
189 self.logstat.send_to_stderr(msg_formatted.get_stderr_output());
191
192 return Some((msg_formatted, self.logstat));
193 }
194}
195
196
197 #[derive(Debug)]
198pub(crate) struct SyslogSocketLockless<D: SyslogDestination>
199{
200 stream: D::SocketTap
201}
202
203impl<D: SyslogDestination> SyslogSocketLockless<D>
204{
205 pub(crate)
206 fn new(logstat: LogStat, net_tap_prov: D) -> SyRes<Self>
207 {
208 let mut sock =
209 D::SocketTap::new(net_tap_prov)?;
210
211 if logstat.contains(LogStat::LOG_NDELAY) == true
212 {
213 sock.connectlog()?;
214 }
215
216 return Ok(
217 Self{ stream: sock }
218 );
219 }
220
221 #[inline]
222 pub(crate)
223 fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
224 {
225 self.stream.disconnectlog()?;
226 self.stream.update_tap_data(tap_data);
227
228 return self.stream.connectlog();
229 }
230
231 #[inline]
232 pub(crate)
233 fn reconnectlog(&mut self) -> SyRes<()>
234 {
235 self.stream.disconnectlog()?;
236 self.stream.connectlog()?;
237
238 return Ok(());
239 }
240
241 #[inline]
242 pub(crate)
243 fn connectlog(&mut self) -> SyRes<()>
244 {
245 return self.stream.connectlog();
246 }
247
248 #[inline]
251 pub(crate)
252 fn disconnectlog(&mut self) -> SyRes<()>
253 {
254 return self.stream.disconnectlog();
255 }
256
257
258
259 #[cfg(target_family = "unix")]
261 fn handle_error(&mut self, e: Error) -> Result<(), SyslogError>
262 {
263 use std::io::ErrorKind;
264 use std::thread::sleep;
265 use std::time::Duration;
266
267 if e.kind() == ErrorKind::NotConnected
269 {
270 self.stream.connectlog()?;
271
272 return Ok(());
273 }
274 else
275 {
276 if D::DEST_TYPE.is_network() == false
277 {
278 if let Some(libc::ENOBUFS) = e.raw_os_error()
279 {
280 if self.stream.get_type().is_priv() == true
282 {
283 use nix::errno::Errno;
284
285 use crate::throw_error_errno;
286
287 throw_error_errno!(Errno::ENOBUFS, "Not enough space in priv socket.");
288 }
289
290 sleep(Duration::from_micros(1));
291
292 return Ok(());
293 }
294 else
295 {
296 self.stream.disconnectlog()?;
298 self.stream.connectlog()?;
299
300 return Ok(());
301 }
303 }
304 else
305 {
306 self.stream.disconnectlog()?;
307 self.stream.connectlog()?;
308
309 return Ok(());
310 }
311 }
312 }
313
314 #[cfg(target_family = "windows")]
316 fn handle_error(&mut self, e: Error) -> Result<(), SyslogError>
317 {
318 use crate::DestinationType;
319 use crate::error::SyslogErrCode;
320
321 if D::DEST_TYPE == DestinationType::Local
322 {
323 let Ok(werr) = e.downcast::<windows::core::Error>()
325 else
326 {
327
328
329 return Err(
330 SyslogError::new(SyslogErrCode::InternalError,
331 "error downcast failed".into())
332 );
333 };
334
335 return Err(
336 SyslogError::new(
337 SyslogErrCode::InternalError,
338 werr.message()
339 )
340 );
341 }
342 else if D::DEST_TYPE == DestinationType::Network
343 {
344 self.stream.disconnectlog()?;
345 self.stream.connectlog()?;
346
347 return Ok(());
348 }
349 else
350 {
351 return Err(
352 SyslogError::new(
353 SyslogErrCode::InternalError,
354 format!("IO error: {}", e)
355 )
356 );
357 }
358
359 }
360
361
362 pub(crate)
371 fn vsyslog1(&mut self, logstat: LogStat, mut msg_formatted: SyslogFormatted) -> SyRes<()>
372 {
373 let fullmsg = msg_formatted.get_full_msg();
374
375 let error =
376 loop
377 {
378 match self.stream.send(fullmsg.as_bytes())
379 {
380 Ok(_) =>
381 return Ok(()),
382 Err(e) =>
383 {
384 match self.handle_error(e)
385 {
386 Ok(_) =>
387 continue,
388 Err(e) =>
389 {
390 logstat.send_to_stderr(&format!("connectlog() failed with {}", e));
391 break e;
392 }
393 }
394 }
395 }
396 };
397
398
399 let _ = logstat.send_to_syscons(msg_formatted.get_stderr_output());
403
404 return Err(error);
405 }
406
407}
408
409
410
411#[cfg(test)]
412mod tests
413{
414 use crate::LOG_MASK;
415
416 use super::*;
417
418 #[test]
419 fn test_log_cons()
420 {
421 let msg = "header msg message payload";
424
425 let lsts = LogStat::LOG_CONS;
426
427 lsts.send_to_syscons(msg);
428
429 return;
430 }
431
432 #[test]
433 fn test_bit_operations()
434 {
435
436 let correct =
437 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
438
439 assert_eq!(correct.facility, LogFacility::LOG_DAEMON);
440 assert_eq!((correct.facility & !LogFacility::LOG_DAEMON), LogFacility::empty());
441 }
442
443 #[test]
458 fn test_set_priority()
459 {
460 let mut correct =
461 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
462
463 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
464
465 assert_eq!(ret, 0xff);
466
467 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
468
469 assert_eq!(ret, LOG_MASK!(Priority::LOG_ERR));
470
471 let ret = correct.is_logmasked(Priority::LOG_WARNING);
472 assert_eq!(ret, true);
473
474 let ret = correct.is_logmasked(Priority::LOG_ERR);
475 assert_eq!(ret, false);
476
477 let ret = correct.is_logmasked(Priority::LOG_CRIT);
478 assert_eq!(ret, true);
479 }
480}
481