1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Execution Server
3 * ---------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
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 * \file
21 * \brief Execution Server Protocol.
22 *//*--------------------------------------------------------------------*/
23
24#include "xsProtocol.hpp"
25
26using std::string;
27using std::vector;
28
29namespace xs
30{
31
32inline deUint32 swapEndianess (deUint32 value)
33{
34	deUint32 b0 = (value >>  0) & 0xFF;
35	deUint32 b1 = (value >>  8) & 0xFF;
36	deUint32 b2 = (value >> 16) & 0xFF;
37	deUint32 b3 = (value >> 24) & 0xFF;
38	return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
39}
40
41template <typename T> T networkToHost (T value);
42template <typename T> T hostToNetwork (T value);
43
44template <> int networkToHost (int value) { return (int)swapEndianess((deUint32)value); }
45template <> int hostToNetwork (int value) { return (int)swapEndianess((deUint32)value); }
46
47class MessageParser
48{
49public:
50	MessageParser (const deUint8* data, int dataSize)
51		: m_data	(data)
52		, m_size	(dataSize)
53		, m_pos		(0)
54	{
55	}
56
57	template <typename T>
58	T get (void)
59	{
60		XS_CHECK_MSG(m_pos + (int)sizeof(T) <= m_size, "Invalid payload size");
61		T netValue;
62		deMemcpy(&netValue, &m_data[m_pos], sizeof(T));
63		m_pos += sizeof(T);
64		return networkToHost(netValue);
65	}
66
67	void getString (std::string& dst)
68	{
69		// \todo [2011-09-30 pyry] We should really send a size parameter instead.
70		while (m_data[m_pos] != 0)
71		{
72			dst += (char)m_data[m_pos++];
73			XS_CHECK_MSG(m_pos < m_size, "Unterminated string payload");
74		}
75
76		m_pos += 1;
77	}
78
79	void assumEnd (void)
80	{
81		if (m_pos != m_size)
82			XS_FAIL("Invalid payload size");
83	}
84
85private:
86	const deUint8*	m_data;
87	int				m_size;
88	int				m_pos;
89};
90
91class MessageWriter
92{
93public:
94	MessageWriter (MessageType msgType, std::vector<deUint8>& buf)
95		: m_buf(buf)
96	{
97		// Place for size.
98		put<int>(0);
99
100		// Write message type.
101		put<int>(msgType);
102	}
103
104	~MessageWriter (void)
105	{
106		finalize();
107	}
108
109	void finalize (void)
110	{
111		DE_ASSERT(m_buf.size() >= MESSAGE_HEADER_SIZE);
112
113		// Write actual size.
114		int size = hostToNetwork((int)m_buf.size());
115		deMemcpy(&m_buf[0], &size, sizeof(int));
116	}
117
118	template <typename T>
119	void put (T value)
120	{
121		T netValue = hostToNetwork(value);
122		size_t curPos = m_buf.size();
123		m_buf.resize(curPos + sizeof(T));
124		deMemcpy(&m_buf[curPos], &netValue, sizeof(T));
125	}
126
127private:
128	std::vector<deUint8>& m_buf;
129};
130
131template <>
132void MessageWriter::put<const char*> (const char* value)
133{
134	int curPos = (int)m_buf.size();
135	int strLen = (int)strlen(value);
136
137	m_buf.resize(curPos + strLen+1);
138	deMemcpy(&m_buf[curPos], &value[0], strLen+1);
139}
140
141void Message::parseHeader (const deUint8* data, int dataSize, MessageType& type, int& size)
142{
143	XS_CHECK_MSG(dataSize >= MESSAGE_HEADER_SIZE, "Incomplete header");
144	MessageParser parser(data, dataSize);
145	size	= (MessageType)parser.get<int>();
146	type	= (MessageType)parser.get<int>();
147}
148
149void Message::writeHeader (MessageType type, int messageSize, deUint8* dst, int bufSize)
150{
151	XS_CHECK_MSG(bufSize >= MESSAGE_HEADER_SIZE, "Incomplete header");
152	int netSize = hostToNetwork(messageSize);
153	int netType = hostToNetwork((int)type);
154	deMemcpy(dst+0, &netSize, sizeof(netSize));
155	deMemcpy(dst+4, &netType, sizeof(netType));
156}
157
158void Message::writeNoData (vector<deUint8>& buf) const
159{
160	MessageWriter writer(type, buf);
161}
162
163HelloMessage::HelloMessage (const deUint8* data, int dataSize)
164	: Message(MESSAGETYPE_HELLO)
165{
166	MessageParser parser(data, dataSize);
167	version = parser.get<int>();
168	parser.assumEnd();
169}
170
171void HelloMessage::write (vector<deUint8>& buf) const
172{
173	MessageWriter writer(type, buf);
174	writer.put(version);
175}
176
177TestMessage::TestMessage (const deUint8* data, int dataSize)
178	: Message(MESSAGETYPE_TEST)
179{
180	MessageParser parser(data, dataSize);
181	parser.getString(test);
182	parser.assumEnd();
183}
184
185void TestMessage::write (vector<deUint8>& buf) const
186{
187	MessageWriter writer(type, buf);
188	writer.put(test.c_str());
189}
190
191ExecuteBinaryMessage::ExecuteBinaryMessage (const deUint8* data, int dataSize)
192	: Message(MESSAGETYPE_EXECUTE_BINARY)
193{
194	MessageParser parser(data, dataSize);
195	parser.getString(name);
196	parser.getString(params);
197	parser.getString(workDir);
198	parser.getString(caseList);
199	parser.assumEnd();
200}
201
202void ExecuteBinaryMessage::write (vector<deUint8>& buf) const
203{
204	MessageWriter writer(type, buf);
205	writer.put(name.c_str());
206	writer.put(params.c_str());
207	writer.put(workDir.c_str());
208	writer.put(caseList.c_str());
209}
210
211ProcessLogDataMessage::ProcessLogDataMessage (const deUint8* data, int dataSize)
212	: Message(MESSAGETYPE_PROCESS_LOG_DATA)
213{
214	MessageParser parser(data, dataSize);
215	parser.getString(logData);
216	parser.assumEnd();
217}
218
219void ProcessLogDataMessage::write (vector<deUint8>& buf) const
220{
221	MessageWriter writer(type, buf);
222	writer.put(logData.c_str());
223}
224
225ProcessLaunchFailedMessage::ProcessLaunchFailedMessage (const deUint8* data, int dataSize)
226	: Message(MESSAGETYPE_PROCESS_LAUNCH_FAILED)
227{
228	MessageParser parser(data, dataSize);
229	parser.getString(reason);
230	parser.assumEnd();
231}
232
233void ProcessLaunchFailedMessage::write (vector<deUint8>& buf) const
234{
235	MessageWriter writer(type, buf);
236	writer.put(reason.c_str());
237}
238
239ProcessFinishedMessage::ProcessFinishedMessage (const deUint8* data, int dataSize)
240	: Message(MESSAGETYPE_PROCESS_FINISHED)
241{
242	MessageParser parser(data, dataSize);
243	exitCode = parser.get<int>();
244	parser.assumEnd();
245}
246
247void ProcessFinishedMessage::write (vector<deUint8>& buf) const
248{
249	MessageWriter writer(type, buf);
250	writer.put(exitCode);
251}
252
253InfoMessage::InfoMessage (const deUint8* data, int dataSize)
254	: Message(MESSAGETYPE_INFO)
255{
256	MessageParser parser(data, dataSize);
257	parser.getString(info);
258	parser.assumEnd();
259}
260
261void InfoMessage::write (vector<deUint8>& buf) const
262{
263	MessageWriter writer(type, buf);
264	writer.put(info.c_str());
265}
266
267} // xs
268