• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ExecServer Client.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "xsDefs.hpp"
25 #include "xsProtocol.hpp"
26 #include "deSocket.hpp"
27 #include "deUniquePtr.hpp"
28 
29 #include "deString.h"
30 
31 #include <memory>
32 #include <sstream>
33 #include <fstream>
34 #include <cstdio>
35 #include <cstdlib>
36 
37 using std::string;
38 using std::vector;
39 
40 namespace xs
41 {
42 
43 typedef de::UniquePtr<Message> ScopedMsgPtr;
44 
45 class SocketError : public Error
46 {
47 public:
SocketError(deSocketResult result,const char * message,const char * file,int line)48 	SocketError (deSocketResult result, const char* message, const char* file, int line)
49 		: Error		(message, deGetSocketResultName(result), file, line)
50 		, m_result	(result)
51 	{
52 	}
53 
getResult(void) const54 	deSocketResult getResult (void) const
55 	{
56 		return m_result;
57 	}
58 
59 private:
60 	deSocketResult m_result;
61 };
62 
63 // Helpers.
sendMessage(de::Socket & socket,const Message & message)64 void sendMessage (de::Socket& socket, const Message& message)
65 {
66 	// Format message.
67 	vector<deUint8> buf;
68 	message.write(buf);
69 
70 	// Write to socket.
71 	size_t pos = 0;
72 	while (pos < buf.size())
73 	{
74 		size_t			numLeft		= buf.size() - pos;
75 		size_t			numSent		= 0;
76 		deSocketResult	result		= socket.send(&buf[pos], numLeft, &numSent);
77 
78 		if (result != DE_SOCKETRESULT_SUCCESS)
79 			throw SocketError(result, "send() failed", __FILE__, __LINE__);
80 
81 		pos += numSent;
82 	}
83 }
84 
readBytes(de::Socket & socket,vector<deUint8> & dst,size_t numBytes)85 void readBytes (de::Socket& socket, vector<deUint8>& dst, size_t numBytes)
86 {
87 	size_t numRead = 0;
88 	dst.resize(numBytes);
89 	while (numRead < numBytes)
90 	{
91 		size_t			numLeft		= numBytes - numRead;
92 		size_t			curNumRead	= 0;
93 		deSocketResult	result		= socket.receive(&dst[numRead], numLeft, &curNumRead);
94 
95 		if (result != DE_SOCKETRESULT_SUCCESS)
96 			throw SocketError(result, "receive() failed", __FILE__, __LINE__);
97 
98 		numRead += curNumRead;
99 	}
100 }
101 
readMessage(de::Socket & socket)102 Message* readMessage (de::Socket& socket)
103 {
104 	// Header.
105 	vector<deUint8> header;
106 	readBytes(socket, header, MESSAGE_HEADER_SIZE);
107 
108 	MessageType	type;
109 	size_t		messageSize;
110 	Message::parseHeader(&header[0], (int)header.size(), type, messageSize);
111 
112 	// Simple messages without any data.
113 	switch (type)
114 	{
115 		case MESSAGETYPE_KEEPALIVE:				return new KeepAliveMessage();
116 		case MESSAGETYPE_PROCESS_STARTED:		return new ProcessStartedMessage();
117 		default:
118 			break; // Read message with data.
119 	}
120 
121 	vector<deUint8> messageBuf;
122 	readBytes(socket, messageBuf, messageSize-MESSAGE_HEADER_SIZE);
123 
124 	switch (type)
125 	{
126 		case MESSAGETYPE_HELLO:					return new HelloMessage(&messageBuf[0], (int)messageBuf.size());
127 		case MESSAGETYPE_TEST:					return new TestMessage(&messageBuf[0], (int)messageBuf.size());
128 		case MESSAGETYPE_PROCESS_LOG_DATA:		return new ProcessLogDataMessage(&messageBuf[0], (int)messageBuf.size());
129 		case MESSAGETYPE_INFO:					return new InfoMessage(&messageBuf[0], (int)messageBuf.size());
130 		case MESSAGETYPE_PROCESS_LAUNCH_FAILED:	return new ProcessLaunchFailedMessage(&messageBuf[0], (int)messageBuf.size());
131 		case MESSAGETYPE_PROCESS_FINISHED:		return new ProcessFinishedMessage(&messageBuf[0], (int)messageBuf.size());
132 		default:
133 			XS_FAIL("Unknown message");
134 	}
135 }
136 
137 class CommandLine
138 {
139 public:
140 	de::SocketAddress	address;
141 	std::string			program;
142 	std::string			params;
143 	std::string			workingDir;
144 	std::string			caseList;
145 	std::string			dstFileName;
146 };
147 
148 class Client
149 {
150 public:
151 						Client		(const CommandLine& cmdLine);
152 						~Client		(void);
153 
154 	void				run			(void);
155 
156 private:
157 	const CommandLine&	m_cmdLine;
158 	de::Socket			m_socket;
159 };
160 
Client(const CommandLine & cmdLine)161 Client::Client (const CommandLine& cmdLine)
162 	: m_cmdLine(cmdLine)
163 {
164 }
165 
~Client(void)166 Client::~Client (void)
167 {
168 }
169 
run(void)170 void Client::run (void)
171 {
172 	// Connect to server.
173 	m_socket.connect(m_cmdLine.address);
174 
175 	printf("Connected to %s:%d!\n", m_cmdLine.address.getHost(), m_cmdLine.address.getPort());
176 
177 	// Open result file.
178 	std::fstream out(m_cmdLine.dstFileName.c_str(), std::fstream::out|std::fstream::binary);
179 
180 	printf("  writing to %s\n", m_cmdLine.dstFileName.c_str());
181 
182 	// Send execution request.
183 	{
184 		ExecuteBinaryMessage msg;
185 
186 		msg.name		= m_cmdLine.program;
187 		msg.params		= m_cmdLine.params;
188 		msg.workDir		= m_cmdLine.workingDir;
189 		msg.caseList	= m_cmdLine.caseList;
190 
191 		sendMessage(m_socket, msg);
192 		printf("  execution request sent.\n");
193 	}
194 
195 	// Run client loop.
196 	bool isRunning = true;
197 	while (isRunning)
198 	{
199 		ScopedMsgPtr msg(readMessage(m_socket));
200 
201 		switch (msg->type)
202 		{
203 			case MESSAGETYPE_HELLO:
204 				printf("  HelloMessage\n");
205 				break;
206 
207 			case MESSAGETYPE_KEEPALIVE:
208 			{
209 				printf("  KeepAliveMessage\n");
210 
211 				// Reply with keepalive.
212 				sendMessage(m_socket, KeepAliveMessage());
213 				break;
214 			}
215 
216 			case MESSAGETYPE_INFO:
217 				printf("  InfoMessage: '%s'\n", static_cast<InfoMessage*>(msg.get())->info.c_str());
218 				break;
219 
220 			case MESSAGETYPE_PROCESS_STARTED:
221 				printf("  ProcessStartedMessage\n");
222 				break;
223 
224 			case MESSAGETYPE_PROCESS_FINISHED:
225 				printf("  ProcessFinished: exit code = %d\n", static_cast<ProcessFinishedMessage*>(msg.get())->exitCode);
226 				isRunning = false;
227 				break;
228 
229 			case MESSAGETYPE_PROCESS_LAUNCH_FAILED:
230 				printf("  ProcessLaunchFailed: '%s'\n", static_cast<ProcessLaunchFailedMessage*>(msg.get())->reason.c_str());
231 				isRunning = false;
232 				break;
233 
234 			case MESSAGETYPE_PROCESS_LOG_DATA:
235 			{
236 				ProcessLogDataMessage* logDataMsg = static_cast<ProcessLogDataMessage*>(msg.get());
237 				printf("  ProcessLogDataMessage: %d bytes\n", (int)logDataMsg->logData.length());
238 				out << logDataMsg->logData;
239 				break;
240 			}
241 
242 			default:
243 				XS_FAIL("Unknown message");
244 				break;
245 		}
246 	}
247 
248 	// Close output file.
249 	out.close();
250 
251 	// Close connection.
252 	m_socket.shutdown();
253 	m_socket.close();
254 
255 	printf("Done!\n");
256 }
257 
parseString(const char * str)258 string parseString (const char* str)
259 {
260 	if (str[0] == '\'' || str[0] == '"')
261 	{
262 		const char*			p		= str;
263 		char				endChar = *p++;
264 		std::ostringstream	o;
265 
266 		while (*p != endChar && *p)
267 		{
268 			if (*p == '\\')
269 			{
270 				switch (p[1])
271 				{
272 					case 0:		DE_ASSERT(DE_FALSE);	break;
273 					case 'n':	o << '\n';				break;
274 					case 't':	o << '\t';				break;
275 					default:	o << p[1];				break;
276 				}
277 
278 				p += 2;
279 			}
280 			else
281 				o << *p++;
282 		}
283 
284 		return o.str();
285 	}
286 	else
287 		return string(str);
288 }
289 
printHelp(const char * binName)290 void printHelp (const char* binName)
291 {
292 	printf("%s:\n", binName);
293 	printf("  --host=[host]          Connect to host [host]\n");
294 	printf("  --port=[name]          Use port [port]\n");
295 	printf("  --program=[program]    Test program\n");
296 	printf("  --params=[params]      Test program params\n");
297 	printf("  --workdir=[dir]        Working directory\n");
298 	printf("  --caselist=[caselist]  Test case list\n");
299 	printf("  --out=filename         Test result file\n");
300 }
301 
runClient(int argc,const char * const * argv)302 int runClient (int argc, const char* const* argv)
303 {
304 	CommandLine cmdLine;
305 
306 	// Defaults.
307 	cmdLine.address.setHost("127.0.0.1");
308 	cmdLine.address.setPort(50016);
309 	cmdLine.dstFileName = "TestResults.qpa";
310 
311 	// Parse command line.
312 	for (int argNdx = 1; argNdx < argc; argNdx++)
313 	{
314 		const char* arg = argv[argNdx];
315 
316 		if (deStringBeginsWith(arg, "--port="))
317 			cmdLine.address.setPort(atoi(arg+7));
318 		else if (deStringBeginsWith(arg, "--host="))
319 			cmdLine.address.setHost(parseString(arg+7).c_str());
320 		else if (deStringBeginsWith(arg, "--program="))
321 			cmdLine.program = parseString(arg+10);
322 		else if (deStringBeginsWith(arg, "--params="))
323 			cmdLine.params = parseString(arg+9);
324 		else if (deStringBeginsWith(arg, "--workdir="))
325 			cmdLine.workingDir = parseString(arg+10);
326 		else if (deStringBeginsWith(arg, "--caselist="))
327 			cmdLine.caseList = parseString(arg+11);
328 		else if  (deStringBeginsWith(arg, "--out="))
329 			cmdLine.dstFileName = parseString(arg+6);
330 		else
331 		{
332 			printHelp(argv[0]);
333 			return -1;
334 		}
335 	}
336 
337 	// Run client.
338 	try
339 	{
340 		Client client(cmdLine);
341 		client.run();
342 	}
343 	catch (const std::exception& e)
344 	{
345 		printf("%s\n", e.what());
346 		return -1;
347 	}
348 
349 	return 0;
350 }
351 
352 } // xs
353 
main(int argc,const char * const * argv)354 int main (int argc, const char* const* argv)
355 {
356 	return xs::runClient(argc, argv);
357 }
358