mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
parent
1a0aa988f1
commit
4fdea34a9d
@ -35,24 +35,20 @@ namespace osquery {
|
||||
// Millisecond latency between initalizing manager pings.
|
||||
const size_t kExtensionInitializeLatency = 20;
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define MODULE_EXTENSION ".dylib"
|
||||
#define EXT_EXTENSION ".ext"
|
||||
#elif defined(WIN32)
|
||||
#define MODULE_EXTENSION ".dll"
|
||||
#define EXT_EXTENSION ".exe"
|
||||
#else
|
||||
#define MODULE_EXTENSION ".so"
|
||||
#define EXT_EXTENSION ".ext"
|
||||
#endif
|
||||
|
||||
enum ExtenableTypes {
|
||||
enum class ExtendableType {
|
||||
EXTENSION = 1,
|
||||
MODULE = 2,
|
||||
};
|
||||
|
||||
const std::map<ExtenableTypes, std::string> kExtendables = {
|
||||
{EXTENSION, EXT_EXTENSION}, {MODULE, MODULE_EXTENSION},
|
||||
using ExtendableTypeSet = std::map<ExtendableType, std::string>;
|
||||
|
||||
const std::map<PlatformType, ExtendableTypeSet> kFileExtensions{
|
||||
{PlatformType::TYPE_WINDOWS,
|
||||
{{ExtendableType::EXTENSION, ".exe"}, {ExtendableType::MODULE, ".dll"}}},
|
||||
{PlatformType::TYPE_LINUX,
|
||||
{{ExtendableType::EXTENSION, ".ext"}, {ExtendableType::MODULE, ".so"}}},
|
||||
{PlatformType::TYPE_OSX,
|
||||
{{ExtendableType::EXTENSION, ".ext"}, {ExtendableType::MODULE, ".dylib"}}},
|
||||
};
|
||||
|
||||
CLI_FLAG(bool, disable_extensions, false, "Disable extension API");
|
||||
@ -60,12 +56,12 @@ CLI_FLAG(bool, disable_extensions, false, "Disable extension API");
|
||||
CLI_FLAG(string,
|
||||
extensions_socket,
|
||||
OSQUERY_SOCKET "osquery.em",
|
||||
"Path to the extensions UNIX domain socket")
|
||||
"Path to the extensions UNIX domain socket");
|
||||
|
||||
CLI_FLAG(string,
|
||||
extensions_autoload,
|
||||
OSQUERY_HOME "/extensions.load",
|
||||
"Optional path to a list of autoloaded & managed extensions")
|
||||
"Optional path to a list of autoloaded & managed extensions");
|
||||
|
||||
CLI_FLAG(string,
|
||||
extensions_timeout,
|
||||
@ -75,12 +71,12 @@ CLI_FLAG(string,
|
||||
CLI_FLAG(string,
|
||||
extensions_interval,
|
||||
"3",
|
||||
"Seconds delay between connectivity checks")
|
||||
"Seconds delay between connectivity checks");
|
||||
|
||||
CLI_FLAG(string,
|
||||
modules_autoload,
|
||||
OSQUERY_HOME "/modules.load",
|
||||
"Optional path to a list of autoloaded registry modules")
|
||||
"Optional path to a list of autoloaded registry modules");
|
||||
|
||||
SHELL_FLAG(string, extension, "", "Path to a single extension to autoload");
|
||||
|
||||
@ -102,31 +98,6 @@ EXTENSION_FLAG_ALIAS(socket, extensions_socket);
|
||||
EXTENSION_FLAG_ALIAS(timeout, extensions_timeout);
|
||||
EXTENSION_FLAG_ALIAS(interval, extensions_interval);
|
||||
|
||||
#ifdef WIN32
|
||||
// Time to wait for a busy named pipe, if it exists
|
||||
#define NAMED_PIPE_WAIT 500
|
||||
|
||||
/**
|
||||
* We cannot use existing methods to determine the lifespan of the
|
||||
* extensions/extensions manager socket. On Windows, the Thrift install is
|
||||
* brittle and does not like a quick connect and disconnect. To compensate, we
|
||||
* use WaitNamedPipe to determine the existence of a named pipe. If the named
|
||||
* pipe does not exist, WaitNamedPipe should error with ERROR_BAD_PATHNAME.
|
||||
*/
|
||||
static Status isNamedPipePathValid(const std::string& path) {
|
||||
if (!boost::starts_with(path, OSQUERY_SOCKET)) {
|
||||
return Status(1, "Bad named pipe name prefix");
|
||||
}
|
||||
|
||||
if ((::WaitNamedPipeA(path.c_str(), NAMED_PIPE_WAIT) == 0) &&
|
||||
(::GetLastError() == ERROR_BAD_PATHNAME)) {
|
||||
return Status(1, "Named pipe path is invalid");
|
||||
}
|
||||
|
||||
return Status(0, "OK");
|
||||
}
|
||||
#endif
|
||||
|
||||
Status applyExtensionDelay(std::function<Status(bool& stop)> predicate) {
|
||||
// Make sure the extension manager path exists, and is writable.
|
||||
size_t delay = 0;
|
||||
@ -153,23 +124,16 @@ Status applyExtensionDelay(std::function<Status(bool& stop)> predicate) {
|
||||
|
||||
Status extensionPathActive(const std::string& path, bool use_timeout = false) {
|
||||
return applyExtensionDelay(([path, &use_timeout](bool& stop) {
|
||||
#ifdef WIN32
|
||||
// This makes sure the pipe exists in some capacity (could be busy at the
|
||||
// moment)
|
||||
if (namedPipeExists(path).ok()) {
|
||||
return Status(0, "OK");
|
||||
}
|
||||
#else
|
||||
if (pathExists(path) && isWritable(path)) {
|
||||
if (socketExists(path)) {
|
||||
try {
|
||||
ExtensionStatus status;
|
||||
auto client = EXManagerClient(path);
|
||||
client.get()->ping(status);
|
||||
return Status(0, "OK");
|
||||
} catch (const std::exception& e) {
|
||||
} catch (const std::exception& /* e */) {
|
||||
// Path might exist without a connected extension or extension manager.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Only check active once if this check does not allow a timeout.
|
||||
if (!use_timeout) {
|
||||
stop = true;
|
||||
@ -221,26 +185,18 @@ void ExtensionWatcher::watch() {
|
||||
// This does NOT use pingExtension to avoid the latency checks applied.
|
||||
ExtensionStatus status;
|
||||
bool core_sane = true;
|
||||
#ifdef WIN32
|
||||
// Check to see if the pipe name is a valid named pipe
|
||||
if (!namedPipeExists(path_).ok()) {
|
||||
core_sane = false;
|
||||
}
|
||||
#else
|
||||
if (isWritable(path_)) {
|
||||
if (socketExists(path_)) {
|
||||
try {
|
||||
auto client = EXManagerClient(path_);
|
||||
// Ping the extension manager until it goes down.
|
||||
client.get()->ping(status);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
} catch (const std::exception& /* e */) {
|
||||
core_sane = false;
|
||||
}
|
||||
} else {
|
||||
// The previously-writable extension socket is not usable.
|
||||
core_sane = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!core_sane) {
|
||||
LOG(INFO) << "Extension watcher ending: osquery core has gone away";
|
||||
@ -261,33 +217,24 @@ void ExtensionManagerWatcher::watch() {
|
||||
ExtensionStatus status;
|
||||
for (const auto& uuid : uuids) {
|
||||
auto path = getExtensionSocket(uuid);
|
||||
#ifdef WIN32
|
||||
// Check to see if the pipe name is a valid named pipe
|
||||
if (!namedPipeExists(path).ok()) {
|
||||
LOG(INFO) << "Extension UUID " << uuid << " ping failed";
|
||||
auto exists = socketExists(path);
|
||||
|
||||
// Immediate fail non-writable paths.
|
||||
failures_[uuid] += 1;
|
||||
}
|
||||
#else
|
||||
// The manager first checks writeability of the extension socket.
|
||||
auto writable = isWritable(path);
|
||||
if (!writable && failures_[uuid] == 0) {
|
||||
if (!exists.ok() && failures_[uuid] == 0) {
|
||||
// If there was never a failure then this is the first attempt.
|
||||
// Allow the extension to be latent and respect the autoload timeout.
|
||||
VLOG(1) << "Extension UUID " << uuid << " initial check failed";
|
||||
writable = extensionPathActive(path, true);
|
||||
exists = extensionPathActive(path, true);
|
||||
}
|
||||
|
||||
// All extensions will have a single failure (and odd use of the counting).
|
||||
// If failures get to 2 then the extension will be removed.
|
||||
failures_[uuid] = 1;
|
||||
if (writable) {
|
||||
if (exists.ok()) {
|
||||
try {
|
||||
auto client = EXClient(path);
|
||||
// Ping the extension until it goes down.
|
||||
client.get()->ping(status);
|
||||
} catch (const std::exception& e) {
|
||||
} catch (const std::exception& /* e */) {
|
||||
failures_[uuid] += 1;
|
||||
continue;
|
||||
}
|
||||
@ -303,7 +250,6 @@ void ExtensionManagerWatcher::watch() {
|
||||
} else {
|
||||
failures_[uuid] = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (const auto& uuid : failures_) {
|
||||
@ -315,28 +261,6 @@ void ExtensionManagerWatcher::watch() {
|
||||
}
|
||||
}
|
||||
|
||||
Status socketWritable(const fs::path& path) {
|
||||
if (pathExists(path).ok()) {
|
||||
if (!isWritable(path).ok()) {
|
||||
return Status(1, "Cannot write extension socket: " + path.string());
|
||||
}
|
||||
|
||||
if (!osquery::remove(path).ok()) {
|
||||
return Status(1, "Cannot remove extension socket: " + path.string());
|
||||
}
|
||||
} else {
|
||||
if (!pathExists(path.parent_path()).ok()) {
|
||||
return Status(1, "Extension socket directory missing: " + path.string());
|
||||
}
|
||||
|
||||
if (!isWritable(path.parent_path()).ok()) {
|
||||
return Status(1, "Cannot create extension socket: " + path.string());
|
||||
}
|
||||
}
|
||||
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
void loadExtensions() {
|
||||
// Disabling extensions will disable autoloading.
|
||||
if (FLAGS_disable_extensions) {
|
||||
@ -365,10 +289,11 @@ void loadModules() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool isFileSafe(std::string& path, ExtenableTypes type) {
|
||||
static bool isFileSafe(std::string& path, ExtendableType type) {
|
||||
boost::trim(path);
|
||||
// A 'type name' may be used in verbose log output.
|
||||
std::string type_name = ((type == EXTENSION) ? "extension" : "module");
|
||||
std::string type_name =
|
||||
((type == ExtendableType::EXTENSION) ? "extension" : "module");
|
||||
if (path.size() == 0 || path[0] == '#' || path[0] == ';') {
|
||||
return false;
|
||||
}
|
||||
@ -378,8 +303,15 @@ static bool isFileSafe(std::string& path, ExtenableTypes type) {
|
||||
VLOG(1) << "Cannot autoload " << type_name << " from directory: " << path;
|
||||
return false;
|
||||
}
|
||||
// The extendables will force an appropriate file path extension.
|
||||
auto& ext = kExtendables.at(type);
|
||||
|
||||
std::string ext;
|
||||
if (isPlatform(PlatformType::TYPE_LINUX)) {
|
||||
ext = kFileExtensions.at(PlatformType::TYPE_LINUX).at(type);
|
||||
} else if (isPlatform(PlatformType::TYPE_OSX)) {
|
||||
ext = kFileExtensions.at(PlatformType::TYPE_OSX).at(type);
|
||||
} else {
|
||||
ext = kFileExtensions.at(PlatformType::TYPE_WINDOWS).at(type);
|
||||
}
|
||||
|
||||
// Only autoload file which were safe at the time of discovery.
|
||||
// If the binary later becomes unsafe (permissions change) then it will fail
|
||||
@ -413,7 +345,7 @@ Status loadExtensions(const std::string& loadfile) {
|
||||
|
||||
if (readFile(loadfile, autoload_paths).ok()) {
|
||||
for (auto& path : osquery::split(autoload_paths, "\n")) {
|
||||
if (isFileSafe(path, EXTENSION)) {
|
||||
if (isFileSafe(path, ExtendableType::EXTENSION)) {
|
||||
// After the path is sanitized the watcher becomes responsible for
|
||||
// forking and executing the extension binary.
|
||||
Watcher::addExtensionPath(path);
|
||||
@ -430,7 +362,7 @@ Status loadModules(const std::string& loadfile) {
|
||||
std::string autoload_paths;
|
||||
if (readFile(loadfile, autoload_paths).ok()) {
|
||||
for (auto& path : osquery::split(autoload_paths, "\n")) {
|
||||
if (isFileSafe(path, MODULE)) {
|
||||
if (isFileSafe(path, ExtendableType::MODULE)) {
|
||||
RegistryModuleLoader loader(path);
|
||||
loader.init();
|
||||
} else {
|
||||
@ -511,15 +443,10 @@ Status startExtension(const std::string& manager_path,
|
||||
return Status(1, "Extension register failed: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
// Now that the uuid is known, try to clean up stale socket paths.
|
||||
// Now that the UUID is known, try to clean up stale socket paths.
|
||||
auto extension_path = getExtensionSocket(ext_status.uuid, manager_path);
|
||||
|
||||
#ifdef WIN32
|
||||
status = isNamedPipePathValid(extension_path);
|
||||
#else
|
||||
status = socketWritable(extension_path);
|
||||
#endif
|
||||
|
||||
status = socketExists(extension_path, true);
|
||||
if (!status) {
|
||||
return status;
|
||||
}
|
||||
@ -723,13 +650,9 @@ Status startExtensionManager() {
|
||||
}
|
||||
|
||||
Status startExtensionManager(const std::string& manager_path) {
|
||||
// Check if the socket location exists.
|
||||
#ifdef WIN32
|
||||
auto status = isNamedPipePathValid(manager_path);
|
||||
#else
|
||||
auto status = socketWritable(manager_path);
|
||||
#endif
|
||||
|
||||
// Check if the socket location is ready for a new Thrift server.
|
||||
// We expect the path to be invalid or a removal attempt to succeed.
|
||||
auto status = socketExists(manager_path, true);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
@ -259,11 +259,11 @@ void ExtensionRunnerCore::startServer(TProcessorRef processor) {
|
||||
|
||||
transport_ = TServerTransportRef(new TPlatformServerSocket(path_));
|
||||
|
||||
#ifndef WIN32
|
||||
// Before starting and after stopping the manager, remove stale sockets.
|
||||
// This is not relevant in Windows
|
||||
removeStalePaths(path_);
|
||||
#endif
|
||||
if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
|
||||
// Before starting and after stopping the manager, remove stale sockets.
|
||||
// This is not relevant in Windows
|
||||
removeStalePaths(path_);
|
||||
}
|
||||
|
||||
// Construct the service's transport, protocol, thread pool.
|
||||
auto transport_fac = TTransportFactoryRef(new TBufferedTransportFactory());
|
||||
|
@ -35,21 +35,19 @@ const int kTimeout = 3000;
|
||||
class ExtensionsTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
#ifdef WIN32
|
||||
socket_path = OSQUERY_SOCKET;
|
||||
#else
|
||||
socket_path = kTestWorkingDirectory;
|
||||
#endif
|
||||
if (isPlatform(PlatformType::TYPE_WINDOWS)) {
|
||||
socket_path = OSQUERY_SOCKET;
|
||||
} else {
|
||||
socket_path = kTestWorkingDirectory;
|
||||
}
|
||||
|
||||
socket_path += "testextmgr" + std::to_string(rand());
|
||||
|
||||
#ifdef WIN32
|
||||
if (namedPipeExists(socket_path).ok()) {
|
||||
#else
|
||||
remove(socket_path);
|
||||
if (pathExists(socket_path).ok()) {
|
||||
#endif
|
||||
throw std::domain_error("Cannot test sockets: " + socket_path);
|
||||
if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
|
||||
remove(socket_path);
|
||||
if (pathExists(socket_path)) {
|
||||
throw std::domain_error("Cannot test sockets: " + socket_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,9 +55,9 @@ class ExtensionsTest : public testing::Test {
|
||||
Dispatcher::stopServices();
|
||||
Dispatcher::joinServices();
|
||||
|
||||
#ifndef WIN32
|
||||
remove(socket_path);
|
||||
#endif
|
||||
if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
|
||||
remove(socket_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool ping(int attempts = 3) {
|
||||
@ -109,15 +107,11 @@ class ExtensionsTest : public testing::Test {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
bool socketExists(const std::string& _socket_path) {
|
||||
bool socketExistsLocal(const std::string& socket_path) {
|
||||
// Wait until the runnable/thread created the socket.
|
||||
int delay = 0;
|
||||
while (delay < kTimeout) {
|
||||
#ifdef WIN32
|
||||
if (namedPipeExists(_socket_path).ok()) {
|
||||
#else
|
||||
if (pathExists(_socket_path).ok() && isReadable(_socket_path).ok()) {
|
||||
#endif
|
||||
if (osquery::socketExists(socket_path).ok()) {
|
||||
return true;
|
||||
}
|
||||
sleepFor(kDelay);
|
||||
@ -135,14 +129,14 @@ TEST_F(ExtensionsTest, test_manager_runnable) {
|
||||
auto status = startExtensionManager(socket_path);
|
||||
EXPECT_TRUE(status.ok());
|
||||
// Call success if the Unix socket was created.
|
||||
EXPECT_TRUE(socketExists(socket_path));
|
||||
EXPECT_TRUE(socketExistsLocal(socket_path));
|
||||
}
|
||||
|
||||
TEST_F(ExtensionsTest, test_extension_runnable) {
|
||||
auto status = startExtensionManager(socket_path);
|
||||
EXPECT_TRUE(status.ok());
|
||||
// Wait for the extension manager to start.
|
||||
EXPECT_TRUE(socketExists(socket_path));
|
||||
EXPECT_TRUE(socketExistsLocal(socket_path));
|
||||
|
||||
// Test the extension manager API 'ping' call.
|
||||
EXPECT_TRUE(ping());
|
||||
@ -151,7 +145,7 @@ TEST_F(ExtensionsTest, test_extension_runnable) {
|
||||
TEST_F(ExtensionsTest, test_extension_start) {
|
||||
auto status = startExtensionManager(socket_path);
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_TRUE(socketExists(socket_path));
|
||||
EXPECT_TRUE(socketExistsLocal(socket_path));
|
||||
|
||||
// Now allow duplicates (for testing, since EM/E are the same).
|
||||
Registry::allowDuplicates(true);
|
||||
@ -170,7 +164,7 @@ TEST_F(ExtensionsTest, test_extension_start) {
|
||||
RouteUUID uuid = (RouteUUID)stoi(status.getMessage(), nullptr, 0);
|
||||
|
||||
// We can test-wait for the extensions's socket to open.
|
||||
EXPECT_TRUE(socketExists(socket_path + "." + std::to_string(uuid)));
|
||||
EXPECT_TRUE(socketExistsLocal(socket_path + "." + std::to_string(uuid)));
|
||||
|
||||
// Then clean up the registry modifications.
|
||||
Registry::removeBroadcast(uuid);
|
||||
@ -194,7 +188,7 @@ CREATE_REGISTRY(ExtensionPlugin, "extension_test");
|
||||
TEST_F(ExtensionsTest, test_extension_broadcast) {
|
||||
auto status = startExtensionManager(socket_path);
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_TRUE(socketExists(socket_path));
|
||||
EXPECT_TRUE(socketExistsLocal(socket_path));
|
||||
|
||||
// This time we're going to add a plugin to the extension_test registry.
|
||||
Registry::add<TestExtensionPlugin>("extension_test", "test_item");
|
||||
@ -224,7 +218,7 @@ TEST_F(ExtensionsTest, test_extension_broadcast) {
|
||||
}
|
||||
|
||||
auto ext_socket = socket_path + "." + std::to_string(uuid);
|
||||
EXPECT_TRUE(socketExists(ext_socket));
|
||||
EXPECT_TRUE(socketExistsLocal(ext_socket));
|
||||
|
||||
// Make sure the EM registered the extension (called in start extension).
|
||||
auto extensions = registeredExtensions();
|
||||
|
@ -106,13 +106,9 @@ const PlatformHandle kInvalidHandle = (PlatformHandle)-1;
|
||||
* Provides a platform agnostic enumeration for file seek operations. These
|
||||
* are translated to the appropriate flags for the underlying platform.
|
||||
*/
|
||||
|
||||
enum SeekMode { PF_SEEK_BEGIN = 0, PF_SEEK_CURRENT, PF_SEEK_END };
|
||||
|
||||
#ifdef WIN32
|
||||
/// Checks for the existence of a named pipe socket
|
||||
Status namedPipeExists(const std::string& path);
|
||||
|
||||
/// Takes a Windows FILETIME object and returns seconds since epoch
|
||||
LONGLONG filetimeToUnixtime(const FILETIME& ft);
|
||||
|
||||
@ -307,6 +303,25 @@ bool platformIsatty(FILE* f);
|
||||
boost::optional<FILE*> platformFopen(const std::string& filename,
|
||||
const std::string& mode);
|
||||
|
||||
/**
|
||||
* @brief Checks for the existence of a named pipe or UNIX socket.
|
||||
*
|
||||
* This method is overloaded to perform two actions. If removal is requested
|
||||
* the success is determined based on the non-existence or successful removal
|
||||
* of the socket path. Otherwise the result is straightforward.
|
||||
*
|
||||
* The removal action is only used when extensions or the extension manager
|
||||
* is first starting.
|
||||
*
|
||||
* @param path The filesystem path to a UNIX socket or Windows named pipe.
|
||||
* @param remove_socket Attempt to remove the socket if it exists.
|
||||
*
|
||||
* @return Success if the socket exists and removal was not requested. False
|
||||
* if the socket exists and removal was requested (and the attempt to remove
|
||||
* had failed).
|
||||
*/
|
||||
Status socketExists(const fs::path& path, bool remove_socket = false);
|
||||
|
||||
/**
|
||||
* @brief Returns the OS root system directory.
|
||||
*
|
||||
|
@ -340,6 +340,30 @@ boost::optional<FILE*> platformFopen(const std::string& filename,
|
||||
return fp;
|
||||
}
|
||||
|
||||
Status socketExists(const fs::path& path, bool remove_socket) {
|
||||
// This implies that the socket is writable.
|
||||
if (pathExists(path).ok()) {
|
||||
if (!isWritable(path).ok()) {
|
||||
return Status(1, "Cannot write extension socket: " + path.string());
|
||||
} else if (remove_socket && !osquery::remove(path).ok()) {
|
||||
return Status(1, "Cannot remove extension socket: " + path.string());
|
||||
}
|
||||
} else {
|
||||
// The path does not exist.
|
||||
if (!pathExists(path.parent_path()).ok()) {
|
||||
return Status(1, "Extension socket directory missing: " + path.string());
|
||||
} else if (!isWritable(path.parent_path()).ok()) {
|
||||
return Status(1, "Cannot create extension socket: " + path.string());
|
||||
}
|
||||
|
||||
// If we are not requesting to remove the socket then this is a failure.
|
||||
if (!remove_socket) {
|
||||
return Status(1, "Socket does not exist");
|
||||
}
|
||||
}
|
||||
return Status(0);
|
||||
}
|
||||
|
||||
fs::path getSystemRoot() {
|
||||
return fs::path("/");
|
||||
}
|
||||
|
@ -1249,13 +1249,26 @@ boost::optional<FILE*> platformFopen(const std::string& filename,
|
||||
return fp;
|
||||
}
|
||||
|
||||
Status namedPipeExists(const std::string& path) {
|
||||
// Wait 500ms for the named pipe status
|
||||
if (::WaitNamedPipeA(path.c_str(), 500) == 0) {
|
||||
/**
|
||||
* @brief The windows implementation introduces a 500ms max wait.
|
||||
*
|
||||
* We cannot use existing methods to determine the lifespan of the
|
||||
* extensions/extensions manager socket. On Windows, the Thrift install is
|
||||
* brittle and does not like a quick connect and disconnect. To compensate, we
|
||||
* use WaitNamedPipe to determine the existence of a named pipe. If the named
|
||||
* pipe does not exist, WaitNamedPipe should error with ERROR_BAD_PATHNAME.
|
||||
*/
|
||||
Status socketExists(const fs::path& path, bool remove_socket) {
|
||||
DWORD timeout = (remove_socket) ? 0 : 500;
|
||||
if (::WaitNamedPipeA(path.string().c_str(), timeout) == 0) {
|
||||
DWORD error = ::GetLastError();
|
||||
if (error == ERROR_BAD_PATHNAME) {
|
||||
return Status(1, "Named pipe path is invalid");
|
||||
} else if (error == ERROR_FILE_NOT_FOUND) {
|
||||
if (remove_socket) {
|
||||
return Status(0);
|
||||
}
|
||||
|
||||
return Status(1, "Named pipe does not exist");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user