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