/*------------------------------------------------------------------------- * Vulkan CTS Framework * -------------------- * * Copyright (c) 2021 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *-------------------------------------------------------------------------*/ #include "vksIPC.hpp" #include "vksStore.hpp" #include "vksClient.hpp" #include namespace vksc_server { namespace ipc { constexpr int DefaultPortIPC = 57323; struct ChildConnection { int id; std::unique_ptr socket; std::atomic& appactive; vector recvb; }; struct PacketsLoop { ChildConnection client; Store& fileStore; template static void SendResponse (ChildConnection& c, T& data) { SendPayloadWithHeader(c.socket.get(), T::Type(), Serialize(data)); } void ProcessPacketsOnServer (ChildConnection& c, u32 type, vector packet) { switch (type) { case StoreContentRequest::Type(): { auto req = Deserialize(packet); bool ok = fileStore.Set(req.name, req.data); StoreContentResponse res; res.status = ok; SendResponse(c, res); } break; case GetContentRequest::Type(): { auto req = Deserialize(packet); vector content; bool ok = fileStore.Get(req.path, content, req.removeAfter); GetContentResponse res; res.status = ok; res.data = std::move(content); SendResponse(c, res); } break; default: throw std::runtime_error("ipc communication error"); } } void Loop () { while (client.socket->isConnected() && client.appactive) { RecvSome(client.socket.get(), client.recvb); auto interpret = [this](u32 type, vector packet) { ProcessPacketsOnServer(client, type, std::move(packet)); }; while (ProccessNetworkData(client.recvb, interpret)) {} } } void operator() () { try { Loop(); } catch (const std::exception& ) { client.socket->close(); } } }; struct ParentImpl { Store fileStore; int m_portOffset; std::thread listenerLoop; std::atomic appActive{true}; void ParentLoop () { vector> clients; int id{}; try { de::SocketAddress addr; addr.setHost("localhost"); addr.setPort(DefaultPortIPC+m_portOffset); de::Socket listener; listener.listen(addr); while (appActive) { remove_erase_if(clients, [](const std::future& c) { return is_ready(c); }); ChildConnection client{ ++id, std::unique_ptr(listener.accept()), appActive, vector{} }; clients.push_back(CreateClientThread(std::move(client))); } } catch (const std::exception&) { appActive = false; } } ParentImpl (const int portOffset) : m_portOffset { portOffset } , listenerLoop {[this](){ParentLoop();}} { } ~ParentImpl () { appActive = false; // Dummy connection to trigger accept() de::SocketAddress addr; addr.setHost("localhost"); addr.setPort(DefaultPortIPC + m_portOffset); de::Socket socket; try { socket.connect(addr); } catch (const de::SocketError&) { } try { socket.close(); } catch (const de::SocketError&) { } listenerLoop.join(); } std::future CreateClientThread (ChildConnection client) { return std::async( PacketsLoop{ std::move(client), fileStore } ); } }; Parent::Parent (const int portOffset) { impl.reset( new ParentImpl(portOffset) ); } Parent::~Parent () { } bool Parent::SetFile (const string& name, const std::vector& content) { return impl->fileStore.Set(name, content); } vector Parent::GetFile (const string& name) { vector content; bool result = impl->fileStore.Get(name, content, false); if (result) return content; else return {}; } struct ChildImpl { ChildImpl(const int portOffset) : m_portOffset(portOffset) { connection.reset(new Server{ "localhost:" + std::to_string(DefaultPortIPC + m_portOffset) }); } int m_portOffset; std::unique_ptr connection; }; Child::Child (const int portOffset) { impl.reset( new ChildImpl(portOffset) ); } Child::~Child () { } bool Child::SetFile (const string& name, const std::vector& content) { StoreContentRequest request; request.name = name; request.data = content; StoreContentResponse response; impl->connection->SendRequest(request, response); return response.status; } std::vector Child::GetFile (const string& name) { GetContentRequest request; request.path = name; request.physicalFile = false; request.removeAfter = false; GetContentResponse response; impl->connection->SendRequest(request, response); if (response.status == true) return response.data; else return {}; } } // ipc } // vksc_server