• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *-------------------------------------------------------------------------*/
20 
21 #include "vksIPC.hpp"
22 #include "vksStore.hpp"
23 #include "vksClient.hpp"
24 
25 #include <future>
26 
27 namespace vksc_server
28 {
29 
30 namespace ipc
31 {
32 
33 constexpr int DefaultPortIPC = 57323;
34 
35 struct ChildConnection
36 {
37     int id;
38     std::unique_ptr<de::Socket> socket;
39     std::atomic<bool> &appactive;
40     vector<u8> recvb;
41 };
42 
43 struct PacketsLoop
44 {
45     ChildConnection client;
46     Store &fileStore;
47 
48     template <typename T>
SendResponsevksc_server::ipc::PacketsLoop49     static void SendResponse(ChildConnection &c, T &data)
50     {
51         SendPayloadWithHeader(c.socket.get(), T::Type(), Serialize(data));
52     }
53 
ProcessPacketsOnServervksc_server::ipc::PacketsLoop54     void ProcessPacketsOnServer(ChildConnection &c, u32 type, vector<u8> packet)
55     {
56         switch (type)
57         {
58         case StoreContentRequest::Type():
59         {
60             auto req = Deserialize<StoreContentRequest>(packet);
61             bool ok  = fileStore.Set(req.name, req.data);
62 
63             StoreContentResponse res;
64             res.status = ok;
65             SendResponse(c, res);
66         }
67         break;
68         case GetContentRequest::Type():
69         {
70             auto req = Deserialize<GetContentRequest>(packet);
71 
72             vector<u8> content;
73             bool ok = fileStore.Get(req.path, content, req.removeAfter);
74 
75             GetContentResponse res;
76             res.status = ok;
77             res.data   = std::move(content);
78             SendResponse(c, res);
79         }
80         break;
81 
82         default:
83             throw std::runtime_error("ipc communication error");
84         }
85     }
86 
Loopvksc_server::ipc::PacketsLoop87     void Loop()
88     {
89         while (client.socket->isConnected() && client.appactive)
90         {
91             RecvSome(client.socket.get(), client.recvb);
92             auto interpret = [this](u32 type, vector<u8> packet)
93             { ProcessPacketsOnServer(client, type, std::move(packet)); };
94             while (ProccessNetworkData(client.recvb, interpret))
95             {
96             }
97         }
98     }
99 
operator ()vksc_server::ipc::PacketsLoop100     void operator()()
101     {
102         try
103         {
104             Loop();
105         }
106         catch (const std::exception &)
107         {
108             client.socket->close();
109         }
110     }
111 };
112 
113 struct ParentImpl
114 {
115     Store fileStore;
116     int m_portOffset;
117     std::thread listenerLoop;
118     std::atomic<bool> appActive{true};
119 
ParentLoopvksc_server::ipc::ParentImpl120     void ParentLoop()
121     {
122         vector<std::future<void>> clients;
123         int id{};
124 
125         try
126         {
127             de::SocketAddress addr;
128             addr.setHost("localhost");
129             addr.setPort(DefaultPortIPC + m_portOffset);
130             de::Socket listener;
131             listener.listen(addr);
132 
133             while (appActive)
134             {
135                 remove_erase_if(clients, [](const std::future<void> &c) { return is_ready(c); });
136                 ChildConnection client{++id, std::unique_ptr<de::Socket>(listener.accept()), appActive, vector<u8>{}};
137                 clients.push_back(CreateClientThread(std::move(client)));
138             }
139         }
140         catch (const std::exception &)
141         {
142             appActive = false;
143         }
144     }
145 
__anon525feff80302vksc_server::ipc::ParentImpl146     ParentImpl(const int portOffset) : m_portOffset{portOffset}, listenerLoop{[this]() { ParentLoop(); }}
147     {
148     }
149 
~ParentImplvksc_server::ipc::ParentImpl150     ~ParentImpl()
151     {
152         appActive = false;
153 
154         // Dummy connection to trigger accept()
155         de::SocketAddress addr;
156         addr.setHost("localhost");
157         addr.setPort(DefaultPortIPC + m_portOffset);
158         de::Socket socket;
159 
160         try
161         {
162             socket.connect(addr);
163         }
164         catch (const de::SocketError &)
165         {
166         }
167 
168         try
169         {
170             socket.close();
171         }
172         catch (const de::SocketError &)
173         {
174         }
175 
176         listenerLoop.join();
177     }
178 
CreateClientThreadvksc_server::ipc::ParentImpl179     std::future<void> CreateClientThread(ChildConnection client)
180     {
181         return std::async(PacketsLoop{std::move(client), fileStore});
182     }
183 };
184 
Parent(const int portOffset)185 Parent::Parent(const int portOffset)
186 {
187     impl.reset(new ParentImpl(portOffset));
188 }
189 
~Parent()190 Parent::~Parent()
191 {
192 }
193 
SetFile(const string & name,const std::vector<u8> & content)194 bool Parent::SetFile(const string &name, const std::vector<u8> &content)
195 {
196     return impl->fileStore.Set(name, content);
197 }
198 
GetFile(const string & name)199 vector<u8> Parent::GetFile(const string &name)
200 {
201     vector<u8> content;
202     bool result = impl->fileStore.Get(name, content, false);
203     if (result)
204         return content;
205     else
206         return {};
207 }
208 
209 struct ChildImpl
210 {
ChildImplvksc_server::ipc::ChildImpl211     ChildImpl(const int portOffset) : m_portOffset(portOffset)
212     {
213         connection.reset(new Server{"localhost:" + std::to_string(DefaultPortIPC + m_portOffset)});
214     }
215 
216     int m_portOffset;
217     std::unique_ptr<Server> connection;
218 };
219 
Child(const int portOffset)220 Child::Child(const int portOffset)
221 {
222     impl.reset(new ChildImpl(portOffset));
223 }
224 
~Child()225 Child::~Child()
226 {
227 }
228 
SetFile(const string & name,const std::vector<u8> & content)229 bool Child::SetFile(const string &name, const std::vector<u8> &content)
230 {
231     StoreContentRequest request;
232     request.name = name;
233     request.data = content;
234     StoreContentResponse response;
235     impl->connection->SendRequest(request, response);
236     return response.status;
237 }
238 
GetFile(const string & name)239 std::vector<u8> Child::GetFile(const string &name)
240 {
241     GetContentRequest request;
242     request.path         = name;
243     request.physicalFile = false;
244     request.removeAfter  = false;
245     GetContentResponse response;
246     impl->connection->SendRequest(request, response);
247     if (response.status == true)
248         return response.data;
249     else
250         return {};
251 }
252 
253 } // namespace ipc
254 
255 } // namespace vksc_server
256