diff --git a/Manager/src/cmdparser.cpp b/Manager/src/cmdparser.cpp index c076a65..00bcf13 100644 --- a/Manager/src/cmdparser.cpp +++ b/Manager/src/cmdparser.cpp @@ -93,8 +93,11 @@ namespace AkVCam { size_t column); std::vector maxColumnsLength(const StringVector &table, size_t width); - void drawTableHLine(const std::vector &columnsLength); - void drawTable(const StringVector &table, size_t width); + void drawTableHLine(const std::vector &columnsLength, + bool toStdErr=false); + void drawTable(const StringVector &table, + size_t width, + bool toStdErr=false); CmdParserCommand *parserCommand(const std::string &command); const CmdParserFlags *parserFlag(const std::vector &cmdFlags, const std::string &flag); @@ -422,6 +425,31 @@ int AkVCam::CmdParser::parse(int argc, char **argv) } } + if (this->d->m_ipcBridge.isBusyFor(command->command)) { + std::cerr << "This operation is not permitted." << std::endl; + std::cerr << "The virtual camera is in use. Stop or close the virtual " + << "camera clients and try again." << std::endl; + std::cerr << std::endl; + auto clients = this->d->m_ipcBridge.clientsPids(); + + if (!clients.empty()) { + std::vector table { + "Pid", + "Executable" + }; + auto columns = table.size(); + + for (auto &pid: clients) { + table.push_back(std::to_string(pid)); + table.push_back(this->d->m_ipcBridge.clientExe(pid)); + } + + this->d->drawTable(table, columns, true); + } + + return -1; + } + if (this->d->m_ipcBridge.needsRoot(command->command) || (command->command == "hack" && arguments.size() >= 2 @@ -619,38 +647,49 @@ std::vector AkVCam::CmdParserPrivate::maxColumnsLength(const AkVCam::Str return lengths; } -void AkVCam::CmdParserPrivate::drawTableHLine(const std::vector &columnsLength) +void AkVCam::CmdParserPrivate::drawTableHLine(const std::vector &columnsLength, + bool toStdErr) { - std::cout << '+'; + std::ostream *out = &std::cout; + + if (toStdErr) + out = &std::cerr; + + *out << '+'; for (auto &len: columnsLength) - std::cout << std::string("-") * (len + 2) << '+'; + *out << std::string("-") * (len + 2) << '+'; - std::cout << std::endl; + *out << std::endl; } void AkVCam::CmdParserPrivate::drawTable(const AkVCam::StringVector &table, - size_t width) + size_t width, + bool toStdErr) { size_t height = table.size() / width; auto columnsLength = this->maxColumnsLength(table, width); - this->drawTableHLine(columnsLength); + this->drawTableHLine(columnsLength, toStdErr); + std::ostream *out = &std::cout; + + if (toStdErr) + out = &std::cerr; for (size_t y = 0; y < height; y++) { - std::cout << "|"; + *out << "|"; for (size_t x = 0; x < width; x++) { auto &element = table[x + y * width]; - std::cout << " " << fill(element, columnsLength[x]) << " |"; + *out << " " << fill(element, columnsLength[x]) << " |"; } - std::cout << std::endl; + *out << std::endl; if (y == 0 && height > 1) - this->drawTableHLine(columnsLength); + this->drawTableHLine(columnsLength, toStdErr); } - this->drawTableHLine(columnsLength); + this->drawTableHLine(columnsLength, toStdErr); } AkVCam::CmdParserCommand *AkVCam::CmdParserPrivate::parserCommand(const std::string &command) @@ -2026,7 +2065,8 @@ int AkVCam::CmdParserPrivate::hacks(const AkVCam::StringMap &flags, "and advanced users only." << std::endl; std::cout << std::endl; std::cout << "WARNING: Unsafe hacks can brick your system, make it " - "unstable, or expose it to a serious security risk. You " + "unstable, or expose it to a serious security risk, " + "remember to make a backup of your files and system. You " "are solely responsible of whatever happens for using " "them. You been warned, don't come and cry later." << std::endl; @@ -2105,7 +2145,8 @@ int AkVCam::CmdParserPrivate::hack(const AkVCam::StringMap &flags, if (!accepted && !this->m_parseable) { std::cout << "WARNING: Applying this hack can brick your system, make " - "it unstable, or expose it to a serious security risk. " + "it unstable, or expose it to a serious security risk, " + "remember to make a backup of your files and system. " "Agreeing to continue, you accept the full responsability " "of whatever happens from now on." << std::endl; diff --git a/VCamUtils/src/ipcbridge.h b/VCamUtils/src/ipcbridge.h index 8f791c9..7a66843 100644 --- a/VCamUtils/src/ipcbridge.h +++ b/VCamUtils/src/ipcbridge.h @@ -91,7 +91,7 @@ namespace AkVCam const std::map &controls) public: - IpcBridge(); + IpcBridge(bool isVCam=false); ~IpcBridge(); /* Server & Client */ @@ -103,7 +103,7 @@ namespace AkVCam std::string logPath(const std::string &logName={}) const; // Register the peer to the global server. - bool registerPeer(); + bool registerPeer(bool isVCam=false); // Unregister the peer to the global server. void unregisterPeer(); @@ -172,6 +172,8 @@ namespace AkVCam // Decrement the count of device listeners bool removeListener(const std::string &deviceId); + bool isBusyFor(const std::string &operation) const; + bool needsRoot(const std::string &operation) const; int sudo(int argc, char **argv) const; diff --git a/VCamUtils/src/utils.h b/VCamUtils/src/utils.h index 0faa6c2..1ae62bf 100644 --- a/VCamUtils/src/utils.h +++ b/VCamUtils/src/utils.h @@ -133,18 +133,22 @@ std::vector m_##CallbackName##Callback; #define AKVCAM_EMIT(owner, CallbackName, ...) \ +{ \ AkLogDebug() << "Emiting: " << #CallbackName << std::endl; \ \ for (auto &callback: owner->m_##CallbackName##Callback) \ if (callback.second) \ callback.second(callback.first, __VA_ARGS__); \ +} #define AKVCAM_EMIT_NOARGS(owner, CallbackName) \ +{ \ AkLogDebug() << "Emiting: " << #CallbackName << std::endl; \ \ for (auto &callback: owner->m_##CallbackName##Callback) \ if (callback.second) \ callback.second(callback.first); \ +} namespace AkVCam { diff --git a/cmio/Assistant/src/assistant.cpp b/cmio/Assistant/src/assistant.cpp index e08d214..824c3b3 100644 --- a/cmio/Assistant/src/assistant.cpp +++ b/cmio/Assistant/src/assistant.cpp @@ -51,7 +51,7 @@ namespace AkVCam class AssistantPrivate { public: - AssistantPeers m_clients; + AssistantPeers m_peers; DeviceConfigs m_deviceConfigs; std::map m_messageHandlers; CFRunLoopTimerRef m_timer {nullptr}; @@ -203,10 +203,10 @@ void AkVCam::AssistantPrivate::peerDied() AkLogFunction(); std::vector deadPeers; - for (auto &client: this->m_clients) { + for (auto &peer: this->m_peers) { auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0); xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_ISALIVE); - auto reply = xpc_connection_send_message_with_reply_sync(client.second, + auto reply = xpc_connection_send_message_with_reply_sync(peer.second, dictionary); xpc_release(dictionary); auto replyType = xpc_get_type(reply); @@ -218,7 +218,7 @@ void AkVCam::AssistantPrivate::peerDied() xpc_release(reply); if (!alive) - deadPeers.push_back(client.first); + deadPeers.push_back(peer.first); } for (auto &peer: deadPeers) @@ -230,15 +230,15 @@ void AkVCam::AssistantPrivate::removePortByName(const std::string &portName) AkLogFunction(); AkLogInfo() << "Port: " << portName << std::endl; - for (auto &peer: this->m_clients) + for (auto &peer: this->m_peers) if (peer.first == portName) { xpc_release(peer.second); - this->m_clients.erase(portName); + this->m_peers.erase(portName); break; } - if (this->m_clients.empty()) + if (this->m_peers.empty()) this->startTimer(); this->releaseDevicesFromPeer(portName); @@ -257,8 +257,8 @@ void AkVCam::AssistantPrivate::releaseDevicesFromPeer(const std::string &portNam xpc_dictionary_set_string(dictionary, "device", config.first.c_str()); xpc_dictionary_set_string(dictionary, "broadcaster", ""); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, dictionary); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, dictionary); xpc_release(dictionary); } else { @@ -298,8 +298,8 @@ void AkVCam::AssistantPrivate::addPort(xpc_connection_t client, xpc_connection_resume(connection); bool ok = true; - for (auto &client: this->m_clients) - if (client.first == portName) { + for (auto &peer: this->m_peers) + if (peer.first == portName) { ok = false; break; @@ -307,7 +307,7 @@ void AkVCam::AssistantPrivate::addPort(xpc_connection_t client, if (ok) { AkLogInfo() << "Adding Peer: " << portName << std::endl; - this->m_clients[portName] = connection; + this->m_peers[portName] = connection; this->stopTimer(); } @@ -349,8 +349,8 @@ void AkVCam::AssistantPrivate::devicesUpdate(xpc_connection_t client, if (xpc_dictionary_get_bool(event, "propagate")) { auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); } @@ -371,8 +371,8 @@ void AkVCam::AssistantPrivate::setBroadcasting(xpc_connection_t client, this->m_deviceConfigs[deviceId].broadcaster = broadcaster; auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); } @@ -387,9 +387,9 @@ void AkVCam::AssistantPrivate::frameReady(xpc_connection_t client, auto reply = xpc_dictionary_create_reply(event); bool ok = true; - for (auto &client: this->m_clients) { - AkLogDebug() << "Sending frame to " << client.first << std::endl; - auto reply = xpc_connection_send_message_with_reply_sync(client.second, + for (auto &peer: this->m_peers) { + AkLogDebug() << "Sending frame to " << peer.first << std::endl; + auto reply = xpc_connection_send_message_with_reply_sync(peer.second, event); auto replyType = xpc_get_type(reply); bool isOk = false; @@ -417,8 +417,8 @@ void AkVCam::AssistantPrivate::pictureUpdated(xpc_connection_t client, AkLogFunction(); auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); } @@ -502,8 +502,8 @@ void AkVCam::AssistantPrivate::listenerAdd(xpc_connection_t client, listeners.push_back(listener); auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); ok = true; @@ -532,8 +532,8 @@ void AkVCam::AssistantPrivate::listenerRemove(xpc_connection_t client, listeners.erase(it); auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); ok = true; @@ -564,8 +564,8 @@ void AkVCam::AssistantPrivate::controlsUpdated(xpc_connection_t client, auto notification = xpc_copy(event); - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, notification); + for (auto &peer: this->m_peers) + xpc_connection_send_message(peer.second, notification); xpc_release(notification); } diff --git a/cmio/VCamIPC/src/ipcbridge.mm b/cmio/VCamIPC/src/ipcbridge.mm index fbf7c43..cced474 100644 --- a/cmio/VCamIPC/src/ipcbridge.mm +++ b/cmio/VCamIPC/src/ipcbridge.mm @@ -134,14 +134,14 @@ namespace AkVCam } } -AkVCam::IpcBridge::IpcBridge() +AkVCam::IpcBridge::IpcBridge(bool isVCam) { AkLogFunction(); this->d = new IpcBridgePrivate(this); auto loglevel = AkVCam::Preferences::logLevel(); AkVCam::Logger::setLogLevel(loglevel); ipcBridgePrivate().add(this); - this->registerPeer(); + this->registerPeer(isVCam); } AkVCam::IpcBridge::~IpcBridge() @@ -191,7 +191,7 @@ std::string AkVCam::IpcBridge::logPath(const std::string &logName) const "/tmp/" + logName + ".log"); } -bool AkVCam::IpcBridge::registerPeer() +bool AkVCam::IpcBridge::registerPeer(bool isVCam) { AkLogFunction(); @@ -271,6 +271,7 @@ bool AkVCam::IpcBridge::registerPeer() xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_ADD_PORT); xpc_dictionary_set_string(dictionary, "port", portName.c_str()); xpc_dictionary_set_connection(dictionary, "connection", messagePort); + xpc_dictionary_set_bool(dictionary, "isvcam", isVCam); reply = xpc_connection_send_message_with_reply_sync(serverMessagePort, dictionary); xpc_release(dictionary); @@ -810,6 +811,26 @@ bool AkVCam::IpcBridge::removeListener(const std::string &deviceId) return status; } +bool AkVCam::IpcBridge::isBusyFor(const std::string &operation) const +{ + static const std::vector operations { + "add-device", + "add-format", + "load", + "remove-device", + "remove-devices", + "remove-format", + "remove-formats", + "set-description", + "update", + "hack" + }; + + auto it = std::find(operations.begin(), operations.end(), operation); + + return it != operations.end() && !this->clientsPids().empty(); +} + bool AkVCam::IpcBridge::needsRoot(const std::string &operation) const { static const std::vector operations; diff --git a/cmio/VirtualCamera/src/plugininterface.cpp b/cmio/VirtualCamera/src/plugininterface.cpp index 33729ac..36c4c1d 100644 --- a/cmio/VirtualCamera/src/plugininterface.cpp +++ b/cmio/VirtualCamera/src/plugininterface.cpp @@ -39,7 +39,7 @@ namespace AkVCam PluginInterface *self; ULONG m_ref; ULONG m_reserved; - IpcBridge m_ipcBridge; + IpcBridge m_ipcBridge {true}; void updateDevices(); static HRESULT QueryInterface(void *self, diff --git a/dshow/Assistant/CMakeLists.txt b/dshow/Assistant/CMakeLists.txt index ede8b79..70a050a 100644 --- a/dshow/Assistant/CMakeLists.txt +++ b/dshow/Assistant/CMakeLists.txt @@ -41,7 +41,9 @@ target_link_libraries(Assistant PlatformUtils advapi32 gdi32 + kernel32 ole32 + psapi shell32 strmiids uuid) diff --git a/dshow/Assistant/src/service.cpp b/dshow/Assistant/src/service.cpp index b1e88e5..b4462d6 100644 --- a/dshow/Assistant/src/service.cpp +++ b/dshow/Assistant/src/service.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -39,13 +40,20 @@ namespace AkVCam { + struct PeerInfo + { + std::string pipeName; + uint64_t pid {0}; + bool isVCam {false}; + }; + struct AssistantDevice { std::string broadcaster; std::vector listeners; }; - typedef std::map AssistantPeers; + typedef std::map AssistantPeers; typedef std::map DeviceConfigs; class ServicePrivate @@ -54,7 +62,7 @@ namespace AkVCam SERVICE_STATUS m_status; SERVICE_STATUS_HANDLE m_statusHandler; MessageServer m_messageServer; - AssistantPeers m_clients; + AssistantPeers m_peers; DeviceConfigs m_deviceConfigs; Timer m_timer; std::mutex m_peerMutex; @@ -64,6 +72,7 @@ namespace AkVCam static void stateChanged(void *userData, MessageServer::State state); void sendStatus(DWORD currentState, DWORD exitCode, DWORD wait); + static std::vector systemProcesses(); static void checkPeers(void *userData); void removePortByName(const std::string &portName); void releaseDevicesFromPeer(const std::string &portName); @@ -80,6 +89,8 @@ namespace AkVCam void listenerAdd(Message *message); void listenerRemove(Message *message); void controlsUpdated(Message *message); + void clients(Message *message); + void client(Message *message); }; GLOBAL_STATIC(ServicePrivate, servicePrivate) @@ -279,8 +290,10 @@ AkVCam::ServicePrivate::ServicePrivate() {AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) }, {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)}, {AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(ServicePrivate::controlsUpdated)}, + {AKVCAM_ASSISTANT_MSG_CLIENTS , AKVCAM_BIND_FUNC(ServicePrivate::clients) }, + {AKVCAM_ASSISTANT_MSG_CLIENT , AKVCAM_BIND_FUNC(ServicePrivate::client) }, }); - this->m_timer.setInterval(60000); + this->m_timer.setInterval(5000); this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers); this->m_timer.start(); } @@ -335,23 +348,41 @@ void AkVCam::ServicePrivate::sendStatus(DWORD currentState, SetServiceStatus(this->m_statusHandler, &this->m_status); } +std::vector AkVCam::ServicePrivate::systemProcesses() +{ + std::vector pids; + + const DWORD nElements = 4096; + DWORD process[nElements]; + memset(process, 0, nElements * sizeof(DWORD)); + DWORD needed = 0; + + if (!EnumProcesses(process, nElements * sizeof(DWORD), &needed)) + return {}; + + size_t nProcess = needed / sizeof(DWORD); + + for (size_t i = 0; i < nProcess; i++) + if (process[i] > 0) + pids.push_back(process[i]); + + return pids; +} + void AkVCam::ServicePrivate::checkPeers(void *userData) { AkLogFunction(); auto self = reinterpret_cast(userData); std::vector deadPeers; + auto pids = systemProcesses(); self->m_peerMutex.lock(); - for (auto &client: self->m_clients) { - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_ISALIVE; - message.dataSize = sizeof(MsgIsAlive); - MessageServer::sendMessage(client.second, &message); - auto requestData = messageData(&message); + for (auto &peer: self->m_peers) { + auto it = std::find(pids.begin(), pids.end(), peer.second.pid); - if (!requestData->alive) - deadPeers.push_back(client.first); + if (it == pids.end()) + deadPeers.push_back(peer.first); } self->m_peerMutex.unlock(); @@ -369,9 +400,9 @@ void AkVCam::ServicePrivate::removePortByName(const std::string &portName) this->m_peerMutex.lock(); - for (auto &peer: this->m_clients) + for (auto &peer: this->m_peers) if (peer.first == portName) { - this->m_clients.erase(portName); + this->m_peers.erase(portName); break; } @@ -397,8 +428,8 @@ void AkVCam::ServicePrivate::releaseDevicesFromPeer(const std::string &portName) (std::min)(config.first.size(), MAX_STRING)); this->m_peerMutex.lock(); - for (auto &client: this->m_clients) - MessageServer::sendMessage(client.second, &message); + for (auto &peer: this->m_peers) + MessageServer::sendMessage(peer.second.pipeName, &message); this->m_peerMutex.unlock(); } else { @@ -437,8 +468,8 @@ void AkVCam::ServicePrivate::addPort(AkVCam::Message *message) this->m_peerMutex.lock(); - for (auto &client: this->m_clients) - if (client.first == portName) { + for (auto &peer: this->m_peers) + if (peer.first == portName) { ok = false; break; @@ -446,7 +477,11 @@ void AkVCam::ServicePrivate::addPort(AkVCam::Message *message) if (ok) { AkLogInfo() << "Adding Peer: " << portName << std::endl; - this->m_clients[portName] = pipeName; + PeerInfo peerInfo; + peerInfo.pipeName = pipeName; + peerInfo.pid = data->pid; + peerInfo.isVCam = data->isVCam; + this->m_peers[portName] = peerInfo; } this->m_peerMutex.unlock(); @@ -480,8 +515,8 @@ void AkVCam::ServicePrivate::devicesUpdate(AkVCam::Message *message) this->m_deviceConfigs = configs; if (data->propagate) - for (auto &client: this->m_clients) - MessageServer::sendMessage(client.second, message); + for (auto &peer: this->m_peers) + MessageServer::sendMessage(peer.second.pipeName, message); this->m_peerMutex.unlock(); } @@ -503,9 +538,9 @@ void AkVCam::ServicePrivate::setBroadCasting(AkVCam::Message *message) this->m_peerMutex.lock(); - for (auto &client: this->m_clients) { + for (auto &peer: this->m_peers) { Message msg(message); - MessageServer::sendMessage(client.second, &msg); + MessageServer::sendMessage(peer.second.pipeName, &msg); } this->m_peerMutex.unlock(); @@ -517,8 +552,8 @@ void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message) AkLogFunction(); this->m_peerMutex.lock(); - for (auto &client: this->m_clients) - MessageServer::sendMessage(client.second, message); + for (auto &peer: this->m_peers) + MessageServer::sendMessage(peer.second.pipeName, message); this->m_peerMutex.unlock(); } @@ -528,8 +563,8 @@ void AkVCam::ServicePrivate::pictureUpdated(AkVCam::Message *message) AkLogFunction(); this->m_peerMutex.lock(); - for (auto &client: this->m_clients) - MessageServer::sendMessage(client.second, message); + for (auto &peer: this->m_peers) + MessageServer::sendMessage(peer.second.pipeName, message); this->m_peerMutex.unlock(); } @@ -616,9 +651,9 @@ void AkVCam::ServicePrivate::listenerAdd(AkVCam::Message *message) this->m_peerMutex.lock(); - for (auto &client: this->m_clients) { + for (auto &peer: this->m_peers) { Message msg(message); - MessageServer::sendMessage(client.second, &msg); + MessageServer::sendMessage(peer.second.pipeName, &msg); } this->m_peerMutex.unlock(); @@ -648,9 +683,9 @@ void AkVCam::ServicePrivate::listenerRemove(AkVCam::Message *message) this->m_peerMutex.lock(); - for (auto &client: this->m_clients) { + for (auto &peer: this->m_peers) { Message msg(message); - MessageServer::sendMessage(client.second, &msg); + MessageServer::sendMessage(peer.second.pipeName, &msg); } this->m_peerMutex.unlock(); @@ -665,12 +700,55 @@ void AkVCam::ServicePrivate::controlsUpdated(AkVCam::Message *message) AkLogFunction(); this->m_peerMutex.lock(); - for (auto &client: this->m_clients) - MessageServer::sendMessage(client.second, message); + for (auto &peer: this->m_peers) + MessageServer::sendMessage(peer.second.pipeName, message); this->m_peerMutex.unlock(); } +void AkVCam::ServicePrivate::clients(AkVCam::Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + this->m_peerMutex.lock(); + data->nclient = 0; + + for (auto &peer: this->m_peers) + if (peer.second.isVCam) + data->nclient++; + + data->status = true; + this->m_peerMutex.unlock(); +} + +void AkVCam::ServicePrivate::client(AkVCam::Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + std::vector pids; + this->m_peerMutex.lock(); + + for (auto &peer: this->m_peers) { + AkLogDebug() << "PID: " << peer.second.pid << std::endl; + AkLogDebug() << "Is vcam: " << peer.second.isVCam << std::endl; + + if (peer.second.isVCam) + pids.push_back(peer.second.pid); + } + + this->m_peerMutex.unlock(); + std::sort(pids.begin(), pids.end()); + + if (data->nclient >= pids.size()) { + data->status = false; + + return; + } + + data->pid = pids[data->nclient]; + data->status = true; +} + DWORD WINAPI controlHandler(DWORD control, DWORD eventType, LPVOID eventData, diff --git a/dshow/PlatformUtils/src/messagecommons.h b/dshow/PlatformUtils/src/messagecommons.h index b960ead..95446cb 100644 --- a/dshow/PlatformUtils/src/messagecommons.h +++ b/dshow/PlatformUtils/src/messagecommons.h @@ -53,6 +53,10 @@ #define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 #define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402 +// Virtual camera clients +#define AKVCAM_ASSISTANT_MSG_CLIENTS 0x500 +#define AKVCAM_ASSISTANT_MSG_CLIENT 0x501 + #define MSG_BUFFER_SIZE 4096 #define MAX_STRING 1024 @@ -133,6 +137,8 @@ namespace AkVCam { char port[MAX_STRING]; char pipeName[MAX_STRING]; + uint64_t pid; + bool isVCam; bool status; }; @@ -181,6 +187,13 @@ namespace AkVCam { char device[MAX_STRING]; }; + + struct MsgClients + { + uint64_t pid; + size_t nclient; + bool status; + }; } #endif // MESSAGECOMMONS_H diff --git a/dshow/PlatformUtils/src/messageserver.cpp b/dshow/PlatformUtils/src/messageserver.cpp index f077106..330370b 100644 --- a/dshow/PlatformUtils/src/messageserver.cpp +++ b/dshow/PlatformUtils/src/messageserver.cpp @@ -47,22 +47,17 @@ namespace AkVCam std::string m_pipeName; std::map m_handlers; MessageServer::ServerMode m_mode {MessageServer::ServerModeReceive}; - MessageServer::PipeState m_pipeState {MessageServer::PipeStateGone}; std::thread m_mainThread; std::vector m_clientsThreads; std::mutex m_mutex; std::condition_variable_any m_exitCheckLoop; - int m_checkInterval {5000}; bool m_running {false}; explicit MessageServerPrivate(MessageServer *self); bool startReceive(bool wait=false); void stopReceive(bool wait=false); - bool startSend(); - void stopSend(); void messagesLoop(); void processPipe(PipeThreadPtr pipeThread, HANDLE pipe); - void checkLoop(); }; } @@ -107,21 +102,6 @@ void AkVCam::MessageServer::setMode(ServerMode mode) this->d->m_mode = mode; } -int AkVCam::MessageServer::checkInterval() const -{ - return this->d->m_checkInterval; -} - -int &AkVCam::MessageServer::checkInterval() -{ - return this->d->m_checkInterval; -} - -void AkVCam::MessageServer::setCheckInterval(int checkInterval) -{ - this->d->m_checkInterval = checkInterval; -} - void AkVCam::MessageServer::setHandlers(const std::map &handlers) { this->d->m_handlers = handlers; @@ -139,8 +119,6 @@ bool AkVCam::MessageServer::start(bool wait) case ServerModeSend: AkLogInfo() << "Starting mode send" << std::endl; - - return this->d->startSend(); } return false; @@ -152,8 +130,6 @@ void AkVCam::MessageServer::stop(bool wait) if (this->d->m_mode == ServerModeReceive) this->d->stopReceive(wait); - else - this->d->stopSend(); } BOOL AkVCam::MessageServer::sendMessage(Message *message, @@ -265,32 +241,6 @@ void AkVCam::MessageServerPrivate::stopReceive(bool wait) this->m_mainThread.join(); } -bool AkVCam::MessageServerPrivate::startSend() -{ - AkLogFunction(); - AkLogDebug() << "Pipe: " << this->m_pipeName << std::endl; - this->m_running = true; - this->m_mainThread = std::thread(&MessageServerPrivate::checkLoop, this); - - return true; -} - -void AkVCam::MessageServerPrivate::stopSend() -{ - AkLogFunction(); - - if (!this->m_running) - return; - - AkLogDebug() << "Pipe: " << this->m_pipeName << std::endl; - this->m_running = false; - this->m_mutex.lock(); - this->m_exitCheckLoop.notify_all(); - this->m_mutex.unlock(); - this->m_mainThread.join(); - this->m_pipeState = MessageServer::PipeStateGone; -} - void AkVCam::MessageServerPrivate::messagesLoop() { AkLogFunction(); @@ -460,34 +410,3 @@ void AkVCam::MessageServerPrivate::processPipe(PipeThreadPtr pipeThread, pipeThread->finished = true; AkLogDebug() << "Pipe thread finished." << std::endl; } - -void AkVCam::MessageServerPrivate::checkLoop() -{ - AkLogFunction(); - - while (this->m_running) { - AkLogDebug() << "Waiting for pipe: " << this->m_pipeName << std::endl; - auto result = WaitNamedPipeA(this->m_pipeName.c_str(), NMPWAIT_NOWAIT); - - if (result - && this->m_pipeState != AkVCam::MessageServer::PipeStateAvailable) { - AkLogInfo() << "Pipe Available: " << this->m_pipeName << std::endl; - this->m_pipeState = AkVCam::MessageServer::PipeStateAvailable; - AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState) - } else if (!result - && this->m_pipeState != AkVCam::MessageServer::PipeStateGone - && GetLastError() != ERROR_SEM_TIMEOUT) { - AkLogInfo() << "Pipe Gone: " << this->m_pipeName << std::endl; - this->m_pipeState = AkVCam::MessageServer::PipeStateGone; - AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState) - } - - if (!this->m_running) - break; - - this->m_mutex.lock(); - this->m_exitCheckLoop.wait_for(this->m_mutex, - std::chrono::milliseconds(this->m_checkInterval)); - this->m_mutex.unlock(); - } -} diff --git a/dshow/PlatformUtils/src/messageserver.h b/dshow/PlatformUtils/src/messageserver.h index 1ab754b..92b7228 100644 --- a/dshow/PlatformUtils/src/messageserver.h +++ b/dshow/PlatformUtils/src/messageserver.h @@ -52,14 +52,7 @@ namespace AkVCam StateStopped }; - enum PipeState - { - PipeStateAvailable, - PipeStateGone - }; - AKVCAM_SIGNAL(StateChanged, State state) - AKVCAM_SIGNAL(PipeStateChanged, PipeState state) public: MessageServer(); @@ -72,9 +65,6 @@ namespace AkVCam ServerMode mode() const; ServerMode &mode(); void setMode(ServerMode mode); - int checkInterval() const; - int &checkInterval(); - void setCheckInterval(int checkInterval); void setHandlers(const std::map &handlers); bool start(bool wait=false); diff --git a/dshow/VCamIPC/src/ipcbridge.cpp b/dshow/VCamIPC/src/ipcbridge.cpp index 1f0a410..3fb10d7 100644 --- a/dshow/VCamIPC/src/ipcbridge.cpp +++ b/dshow/VCamIPC/src/ipcbridge.cpp @@ -143,14 +143,14 @@ namespace AkVCam static const size_t maxBufferSize = sizeof(Frame) + 3 * maxFrameSize; } -AkVCam::IpcBridge::IpcBridge() +AkVCam::IpcBridge::IpcBridge(bool isVCam) { AkLogFunction(); this->d = new IpcBridgePrivate(this); auto loglevel = AkVCam::Preferences::logLevel(); AkVCam::Logger::setLogLevel(loglevel); this->d->m_mainServer.start(); - this->registerPeer(); + this->registerPeer(isVCam); this->d->updateDeviceSharedProperties(); this->d->startServiceStatusCheck(); } @@ -204,7 +204,7 @@ std::string AkVCam::IpcBridge::logPath(const std::string &logName) const return AkVCam::Preferences::readString("logfile", defaultLogFile); } -bool AkVCam::IpcBridge::registerPeer() +bool AkVCam::IpcBridge::registerPeer(bool isVCam) { AkLogFunction(); @@ -254,6 +254,8 @@ bool AkVCam::IpcBridge::registerPeer() memcpy(addData->pipeName, pipeName.c_str(), (std::min)(pipeName.size(), MAX_STRING)); + addData->pid = GetCurrentProcessId(); + addData->isVCam = isVCam; if (!MessageServer::sendMessage("\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME, &message)) { @@ -488,10 +490,11 @@ std::vector AkVCam::IpcBridge::listeners(const std::string &deviceI if (!data->status) return {}; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER; + size_t nlisteners = data->nlistener; + message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER; std::vector listeners; - for (size_t i = 0; i < data->nlistener; i++) { + for (size_t i = 0; i < nlisteners; i++) { data->nlistener = i; if (!this->d->m_mainServer.sendMessage(&message)) @@ -509,98 +512,36 @@ std::vector AkVCam::IpcBridge::listeners(const std::string &deviceI std::vector AkVCam::IpcBridge::clientsPids() const { AkLogFunction(); - auto pluginPath = locatePluginPath(); - AkLogDebug() << "Plugin path: " << pluginPath << std::endl; - if (pluginPath.empty()) + Message message; + message.messageId = AKVCAM_ASSISTANT_MSG_CLIENTS; + message.dataSize = sizeof(MsgClients); + auto data = messageData(&message); + + if (!this->d->m_mainServer.sendMessage(&message)) return {}; - std::vector plugins; - - // First check for the existence of the main plugin binary. - auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll"; - AkLogDebug() << "Plugin binary: " << path << std::endl; - - if (fileExists(path)) - plugins.push_back(path); - - // Check if the alternative architecture plugin exists. - auto altPlugin = this->d->alternativePlugin(); - - if (!altPlugin.empty()) - plugins.push_back(path); - - if (plugins.empty()) + if (!data->status) return {}; + auto currentPid = GetCurrentProcessId(); + size_t nclients = data->nclient; + message.messageId = AKVCAM_ASSISTANT_MSG_CLIENT; std::vector pids; - const DWORD nElements = 4096; - DWORD process[nElements]; - memset(process, 0, nElements * sizeof(DWORD)); - DWORD needed = 0; + for (size_t i = 0; i < nclients; i++) { + data->nclient = i; - if (!EnumProcesses(process, nElements * sizeof(DWORD), &needed)) - return {}; - - size_t nProcess = needed / sizeof(DWORD); - auto currentPid = GetCurrentProcessId(); - - for (size_t i = 0; i < nProcess; i++) { - auto processHnd = OpenProcess(PROCESS_QUERY_INFORMATION - | PROCESS_VM_READ, - FALSE, - process[i]); - - if (!processHnd) + if (!this->d->m_mainServer.sendMessage(&message)) continue; - char processName[MAX_PATH]; - memset(&processName, 0, sizeof(MAX_PATH)); + if (!data->status) + continue; - if (GetModuleBaseNameA(processHnd, - nullptr, - processName, - MAX_PATH)) - AkLogDebug() << "Enumerating modules for '" << processName << "'" << std::endl; + if (data->pid == currentPid) + continue; - HMODULE modules[nElements]; - memset(modules, 0, nElements * sizeof(HMODULE)); - - if (EnumProcessModules(processHnd, - modules, - nElements * sizeof(HMODULE), - &needed)) { - size_t nModules = - std::min(needed / sizeof(HMODULE), nElements); - - for (size_t j = 0; j < nModules; j++) { - CHAR moduleName[MAX_PATH]; - memset(moduleName, 0, MAX_PATH * sizeof(CHAR)); - - if (GetModuleFileNameExA(processHnd, - modules[j], - moduleName, - MAX_PATH)) { - auto it = std::find(plugins.begin(), - plugins.end(), - moduleName); - - if (it != plugins.end()) { - auto pidsIt = std::find(pids.begin(), - pids.end(), - process[i]); - - if (process[i] > 0 - && pidsIt == pids.end() - && process[i] != currentPid) - pids.push_back(process[i]); - } - } - } - } - - CloseHandle(processHnd); + pids.push_back(data->pid); } return pids; @@ -875,6 +816,26 @@ bool AkVCam::IpcBridge::removeListener(const std::string &deviceId) return data->status; } +bool AkVCam::IpcBridge::isBusyFor(const std::string &operation) const +{ + static const std::vector operations { + "add-device", + "add-format", + "load", + "remove-device", + "remove-devices", + "remove-format", + "remove-formats", + "set-description", + "update", + "hack" + }; + + auto it = std::find(operations.begin(), operations.end(), operation); + + return it != operations.end() && !this->clientsPids().empty(); +} + bool AkVCam::IpcBridge::needsRoot(const std::string &operation) const { static const std::vector operations { diff --git a/dshow/VirtualCamera/src/basefilter.cpp b/dshow/VirtualCamera/src/basefilter.cpp index a9fc23e..5396b97 100644 --- a/dshow/VirtualCamera/src/basefilter.cpp +++ b/dshow/VirtualCamera/src/basefilter.cpp @@ -62,7 +62,7 @@ namespace AkVCam std::string m_vendor; std::string m_filterName; IFilterGraph *m_filterGraph {nullptr}; - IpcBridge m_ipcBridge; + IpcBridge m_ipcBridge {true}; IpcBridge::ServerState m_serverState {IpcBridge::ServerStateGone}; BaseFilterPrivate(BaseFilter *self,