Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
huguesBouvier authored and Ubuntu committed Oct 16, 2021
1 parent c5d6176 commit b72a41c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 78 deletions.
19 changes: 19 additions & 0 deletions edgelet/aziot-edged/src/workload_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@ where
) -> Result<(), Error> {
let label = "work".to_string();

// If a listener has already been created, remove previous listener.
// This avoid the launch of 2 listeners.
// We chose to remove instead and create a new one instead of
// just return and say, one listener has already been created:
// We chose to remove because a listener could crash without getting removed correctly.
// That could make the module crash. Then that module would be restarted without ever going to
// "stop"
// There is still a chance that 2 concurrent servers are launch with concurrence,
// But it is extremely unlikely and anyway doesn't have any side effect expect memory footprint.
if let Some(shutdown_sender) = self.shutdown_senders.remove(module_id) {
info!(
"Listener {} already started, removing old listener",
module_id
);
shutdown_sender
.send(())
.map_err(|()| Error::from(ErrorKind::WorkloadService))?;
}

let (shutdown_sender, shutdown_receiver) = oneshot::channel();

self.shutdown_senders
Expand Down
1 change: 0 additions & 1 deletion edgelet/edgelet-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ systemd = { path = "../systemd" }
hyperlocal = "0.6"
libc = "0.2"
nix = "0.14"
scopeguard = "0.3.3"
tokio-uds = "0.2"

[dev-dependencies]
Expand Down
121 changes: 44 additions & 77 deletions edgelet/edgelet-http/src/unix.rs
Original file line number Diff line number Diff line change
@@ -1,106 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.

use std::fs;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
use std::os::unix::prelude::PermissionsExt;
use std::path::Path;

use failure::ResultExt;
use log::{debug, error};
#[cfg(unix)]
use nix::sys::stat::{umask, Mode};
#[cfg(unix)]
use scopeguard::defer;
#[cfg(unix)]
use tokio_uds::UnixListener;

use crate::error::{Error, ErrorKind};
use crate::util::{incoming::Incoming, socket_file_exists};

pub fn listener<P: AsRef<Path>>(path: P, unix_socket_permission: u32) -> Result<Incoming, Error> {
let listener = if socket_file_exists(path.as_ref()) {
// get the previous file's metadata
#[cfg(unix)]
let metadata = get_metadata(path.as_ref())?;

debug!("unlinking {}...", path.as_ref().display());
fs::remove_file(&path)
.with_context(|_| ErrorKind::Path(path.as_ref().display().to_string()))?;
debug!("unlinked {}", path.as_ref().display());

#[cfg(unix)]
let prev = set_umask(&metadata, path.as_ref());
#[cfg(unix)]
defer! {{ umask(prev); }}

debug!("binding {}...", path.as_ref().display());

let listener = UnixListener::bind(&path)
.with_context(|_| ErrorKind::Path(path.as_ref().display().to_string()))?;
debug!("bound {}", path.as_ref().display());

Incoming::Unix(listener)
} else {
// If parent doesn't exist, create it and socket will be created inside.
if let Some(parent) = path.as_ref().parent() {
if !parent.exists() {
fs::create_dir_all(parent).with_context(|err| {
error!("Cannot create directory, error: {}", err);
ErrorKind::Path(path.as_ref().display().to_string())
})?;
}
let path = path.as_ref();

if socket_file_exists(path) {
debug!("unlinking {}...", path.display());
let err1 = fs::remove_file(path).err();
let err2 = fs::remove_dir_all(path).err();
if let Some((err1, err2)) = err1.zip(err2) {
error!("Could not unlink existing socket: [{}] [{}]", err1, err2);
return Err(ErrorKind::Path(path.display().to_string()).into());
}
debug!("unlinked {}", path.display());
}

let listener = UnixListener::bind(&path)
.with_context(|_| ErrorKind::Path(path.as_ref().display().to_string()))?;

fs::set_permissions(
path.as_ref(),
fs::Permissions::from_mode(unix_socket_permission),
)
.map_err(|err| {
error!("Cannot set directory permissions: {}", err);
ErrorKind::Path(path.as_ref().display().to_string())
// If parent doesn't exist, create it and socket will be created inside.
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).with_context(|err| {
error!("Cannot create directory, error: {}", err);
ErrorKind::Path(path.display().to_string())
})?;
}

Incoming::Unix(listener)
};

Ok(listener)
}

#[cfg(unix)]
fn get_metadata(path: &Path) -> Result<fs::Metadata, Error> {
let metadata =
fs::metadata(path).with_context(|_| ErrorKind::Path(path.display().to_string()))?;
debug!("read metadata {:?} for {}", metadata, path.display());
Ok(metadata)
}

#[cfg(unix)]
fn set_umask(metadata: &fs::Metadata, path: &Path) -> Mode {
#[cfg(target_os = "macos")]
#[allow(clippy::cast_possible_truncation)]
let mode = Mode::from_bits_truncate(metadata.mode() as u16);

#[cfg(not(target_os = "macos"))]
let mode = Mode::from_bits_truncate(metadata.mode());

let mut mask = Mode::all();
mask.toggle(mode);
let listener =
UnixListener::bind(&path).with_context(|_| ErrorKind::Path(path.display().to_string()))?;
debug!("bound {}", path.display());

debug!("settings permissions {:#o} for {}...", mode, path.display());
fs::set_permissions(path, fs::Permissions::from_mode(unix_socket_permission)).map_err(
|err| {
error!("Cannot set directory permissions: {}", err);
ErrorKind::Path(path.display().to_string())
},
)?;

umask(mask)
Ok(Incoming::Unix(listener))
}

#[cfg(test)]
#[cfg(unix)]
mod tests {
use super::{listener, MetadataExt};

use super::listener;
use std::fs::OpenOptions;
use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::OpenOptionsExt;

use futures::Stream;
Expand All @@ -126,7 +79,21 @@ mod tests {
let _srv = listener.for_each(move |(_socket, _addr)| Ok(()));

let file_stat = stat(&path).unwrap();
assert_eq!(0o600, file_stat.st_mode & 0o777);
assert_eq!(0o666, file_stat.st_mode & 0o777);

dir.close().unwrap();
}

#[test]
fn test_socket_not_created() {
let dir = tempdir().unwrap();
let path = dir.path().join("dummy_socket.sock");

let listener = listener(&path, 0o666).unwrap();
let _srv = listener.for_each(move |(_socket, _addr)| Ok(()));

let file_stat = stat(&path).unwrap();
assert_eq!(0o666, file_stat.st_mode & 0o777);

dir.close().unwrap();
}
Expand Down

0 comments on commit b72a41c

Please sign in to comment.