-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve handling of systemd activation #50
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ static SOCKET_PATH: &str = "/tmp/security-daemon-socket"; | |
/// | ||
/// Only works on Unix systems. | ||
pub struct DomainSocketListener { | ||
listener: Option<UnixListener>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense to remove that to me! As the |
||
listener: UnixListener, | ||
timeout: Duration, | ||
} | ||
|
||
|
@@ -42,36 +42,39 @@ impl DomainSocketListener { | |
/// - if a file/socket exists at the path specified for the socket and `remove_file` | ||
/// fails | ||
/// - if binding to the socket path fails | ||
fn init(&mut self) { | ||
if cfg!(feature = "systemd-daemon") { | ||
// The PARSEC service is socket activated (see parsec.socket file). | ||
// systemd creates the PARSEC service giving it an initialised socket as the file | ||
// descriptor number 3 (see sd_listen_fds(3) man page). | ||
// If an instance of PARSEC compiled with the "systemd-daemon" feature is run directly | ||
// instead of by systemd, this call will still work but the next accept call on the | ||
// UnixListener will generate a Linux error 9 (Bad file number), as checked below. | ||
unsafe { | ||
self.listener = Some(UnixListener::from_raw_fd(3)); | ||
} | ||
} else { | ||
let socket = Path::new(SOCKET_PATH); | ||
pub fn new(timeout: Duration) -> Self { | ||
// If this PARSEC instance was socket activated (see the `parsec.socket` | ||
// file), the listener will be opened by systemd and passed to the | ||
// process. | ||
// If PARSEC was service activated or not started under systemd, this | ||
// will return `0`. | ||
let listener = | ||
match sd_notify::listen_fds().expect("Could not retrieve listener from systemd") { | ||
0 => { | ||
let socket = Path::new(SOCKET_PATH); | ||
|
||
if socket.exists() { | ||
fs::remove_file(&socket).unwrap(); | ||
} | ||
if socket.exists() { | ||
fs::remove_file(&socket).unwrap(); | ||
} | ||
|
||
let listener_val = match UnixListener::bind(SOCKET_PATH) { | ||
Ok(listener) => listener, | ||
Err(err) => panic!(err), | ||
}; | ||
let listener = | ||
UnixListener::bind(SOCKET_PATH).expect("Could not bind listen socket"); | ||
listener | ||
.set_nonblocking(true) | ||
.expect("Could not set the socket as non-blocking"); | ||
|
||
// Set the socket as non-blocking. | ||
listener_val | ||
.set_nonblocking(true) | ||
.expect("Could not set the socket as non-blocking"); | ||
lnicola marked this conversation as resolved.
Show resolved
Hide resolved
|
||
listener | ||
} | ||
1 => { | ||
// No need to set the socket as non-blocking, parsec.service | ||
// already requests that. | ||
let nfd = sd_notify::SD_LISTEN_FDS_START; | ||
unsafe { UnixListener::from_raw_fd(nfd) } | ||
} | ||
_ => panic!("Received too many file descriptors"), | ||
}; | ||
|
||
self.listener = Some(listener_val); | ||
} | ||
Self { listener, timeout } | ||
} | ||
} | ||
|
||
|
@@ -81,44 +84,30 @@ impl Listen for DomainSocketListener { | |
} | ||
|
||
fn accept(&self) -> Option<Box<dyn ReadWrite + Send>> { | ||
if let Some(listener) = &self.listener { | ||
let stream_result = listener.accept(); | ||
match stream_result { | ||
Ok((stream, _)) => { | ||
if let Err(err) = stream.set_read_timeout(Some(self.timeout)) { | ||
error!("Failed to set read timeout ({})", err); | ||
None | ||
} else if let Err(err) = stream.set_write_timeout(Some(self.timeout)) { | ||
error!("Failed to set write timeout ({})", err); | ||
None | ||
} else if let Err(err) = stream.set_nonblocking(false) { | ||
error!("Failed to set stream as blocking ({})", err); | ||
None | ||
} else { | ||
Some(Box::from(stream)) | ||
} | ||
} | ||
Err(err) => { | ||
if cfg!(feature = "systemd-daemon") { | ||
// When run as a systemd daemon, a file descriptor mapping to the Domain Socket | ||
// should have been passed to this process. | ||
if let Some(os_error) = err.raw_os_error() { | ||
// On Linux, 9 is EBADF (Bad file number) | ||
if os_error == 9 { | ||
panic!("The Unix Domain Socket file descriptor (number 3) should have been given to this process."); | ||
} | ||
} | ||
} | ||
// Check if the error is because no connections are currently present. | ||
if err.kind() != ErrorKind::WouldBlock { | ||
// Only log the real errors. | ||
error!("Failed to connect with a UnixStream ({})", err); | ||
} | ||
let stream_result = self.listener.accept(); | ||
match stream_result { | ||
Ok((stream, _)) => { | ||
if let Err(err) = stream.set_read_timeout(Some(self.timeout)) { | ||
error!("Failed to set read timeout ({})", err); | ||
None | ||
} else if let Err(err) = stream.set_write_timeout(Some(self.timeout)) { | ||
error!("Failed to set write timeout ({})", err); | ||
None | ||
} else if let Err(err) = stream.set_nonblocking(false) { | ||
error!("Failed to set stream as blocking ({})", err); | ||
None | ||
} else { | ||
Some(Box::from(stream)) | ||
} | ||
} | ||
Err(err) => { | ||
// Check if the error is because no connections are currently present. | ||
if err.kind() != ErrorKind::WouldBlock { | ||
// Only log the real errors. | ||
error!("Failed to connect with a UnixStream ({})", err); | ||
} | ||
None | ||
} | ||
} else { | ||
panic!("The Unix Domain Socket has not been initialised."); | ||
} | ||
} | ||
} | ||
|
@@ -139,12 +128,7 @@ impl DomainSocketListenerBuilder { | |
} | ||
|
||
pub fn build(self) -> DomainSocketListener { | ||
let mut listener = DomainSocketListener { | ||
timeout: self.timeout.expect("FrontEndHandler missing"), | ||
listener: None, | ||
}; | ||
listener.init(); | ||
|
||
listener | ||
let timeout = self.timeout.expect("The listener timeout was not set"); | ||
DomainSocketListener::new(timeout) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the crate choose a double-licensing option (Apache-2.0 OR MIT), as the following (example
uuid
):We explicitely make a choice and choose in that file to use Apache-2.0 license. If it is AND, we keep the two licenses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can revert the licensing change, but that sounds like a false dichotomy. All of those crates are dual-licensed, in the sense that you can pick either of them. The difference you noticed is in the manifest. People used to write
MIT/Apache-2.0
, but nowMIT OR Apache-2.0
is preferred because it's "more machine-readable". Both are equivalent, see the comment in https://doc.rust-lang.org/stable/cargo/reference/manifest.html#package-metadata.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the pointer. What I understand from that is that is is more explicit to use AND or OR instead of a slash (
/
) but not that they both mean the same thing 😛But I do not know if the licenses are for use of the library or contributions to it, and if it is for contributions that means that there could be files both licensed under MIT and Apache-2.0 in the same library.
In that case, it is probably better to use AND everywhere as you changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
OR
would be a better fit.It's for the crate, and dual-licensing means that the user of the crate gets to pick one of the licenses (or both) that fits their project better. By contributing to a crate you implicitly admit that your changes will be licensed under the crate's terms (e.g. both MIT and Apache-2.0).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would not it feel weird to have OR on this file as we are building a binary and not re-distributing the crates? As in, we are the last one in the chain so should not we make that decision between Apache-2.0 or MIT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to say "PARSEC is licensed under Apache-2.0 and uses the following dependencies, with their associated licenses", but I am not a lawyer :-).