• 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) { ProcessPacketsOnServer(client, type, std::move(packet)); };
93 			while (ProccessNetworkData(client.recvb, interpret)) {}
94 		}
95 	}
96 
operator ()vksc_server::ipc::PacketsLoop97 	void operator() ()
98 	{
99 		try { Loop(); }
100 		catch (const std::exception& ) { client.socket->close(); }
101 	}
102 };
103 
104 struct ParentImpl
105 {
106 	Store				fileStore;
107 	int					m_portOffset;
108 	std::thread			listenerLoop;
109 	std::atomic<bool>	appActive{true};
110 
ParentLoopvksc_server::ipc::ParentImpl111 	void ParentLoop ()
112 	{
113 		vector<std::future<void>> clients;
114 		int id{};
115 
116 		try
117 		{
118 			de::SocketAddress addr;
119 			addr.setHost("localhost");
120 			addr.setPort(DefaultPortIPC+m_portOffset);
121 			de::Socket listener;
122 			listener.listen(addr);
123 
124 			while (appActive)
125 			{
126 				remove_erase_if(clients, [](const std::future<void>& c) { return is_ready(c); });
127 				ChildConnection client{ ++id, std::unique_ptr<de::Socket>(listener.accept()), appActive, vector<u8>{} };
128 				clients.push_back(CreateClientThread(std::move(client)));
129 			}
130 		}
131 		catch (const std::exception&) { appActive = false; }
132 	}
133 
ParentImplvksc_server::ipc::ParentImpl134 	ParentImpl (const int portOffset)
135 		: m_portOffset { portOffset }
__anon06298fc20302vksc_server::ipc::ParentImpl136 		, listenerLoop {[this](){ParentLoop();}}
137 	{
138 	}
139 
~ParentImplvksc_server::ipc::ParentImpl140 	~ParentImpl ()
141 	{
142 		appActive = false;
143 
144 		// Dummy connection to trigger accept()
145 		de::SocketAddress addr;
146 		addr.setHost("localhost");
147 		addr.setPort(DefaultPortIPC + m_portOffset);
148 		de::Socket socket;
149 
150 		try
151 		{
152 			socket.connect(addr);
153 		}
154 		catch (const de::SocketError&)
155 		{
156 		}
157 
158 		try
159 		{
160 			socket.close();
161 		}
162 		catch (const de::SocketError&)
163 		{
164 		}
165 
166 		listenerLoop.join();
167 	}
168 
CreateClientThreadvksc_server::ipc::ParentImpl169 	std::future<void> CreateClientThread (ChildConnection client)
170 	{
171 		return std::async( PacketsLoop{ std::move(client), fileStore } );
172 	}
173 };
174 
Parent(const int portOffset)175 Parent::Parent (const int portOffset)
176 {
177 	impl.reset( new ParentImpl(portOffset) );
178 }
179 
~Parent()180 Parent::~Parent ()
181 {
182 }
183 
184 
SetFile(const string & name,const std::vector<u8> & content)185 bool Parent::SetFile (const string& name, const std::vector<u8>& content)
186 {
187 	return impl->fileStore.Set(name, content);
188 }
189 
GetFile(const string & name)190 vector<u8> Parent::GetFile (const string& name)
191 {
192 	vector<u8> content;
193 	bool result = impl->fileStore.Get(name, content, false);
194 	if (result) return content;
195 	else return {};
196 }
197 
198 struct ChildImpl
199 {
ChildImplvksc_server::ipc::ChildImpl200 	ChildImpl(const int portOffset)
201 		: m_portOffset(portOffset)
202 	{
203 		connection.reset(new Server{ "localhost:" + std::to_string(DefaultPortIPC + m_portOffset) });
204 	}
205 
206 	int m_portOffset;
207 	std::unique_ptr<Server> connection;
208 };
209 
Child(const int portOffset)210 Child::Child (const int portOffset)
211 {
212 	impl.reset( new ChildImpl(portOffset) );
213 }
214 
~Child()215 Child::~Child ()
216 {
217 }
218 
SetFile(const string & name,const std::vector<u8> & content)219 bool Child::SetFile (const string& name, const std::vector<u8>& content)
220 {
221 	StoreContentRequest request;
222 	request.name = name;
223 	request.data = content;
224 	StoreContentResponse response;
225 	impl->connection->SendRequest(request, response);
226 	return response.status;
227 }
228 
GetFile(const string & name)229 std::vector<u8> Child::GetFile (const string& name)
230 {
231 	GetContentRequest request;
232 	request.path = name;
233 	request.physicalFile = false;
234 	request.removeAfter = false;
235 	GetContentResponse response;
236 	impl->connection->SendRequest(request, response);
237 	if (response.status == true) return response.data;
238 	else return {};
239 }
240 
241 } // ipc
242 
243 } // vksc_server
244