13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program Test Executor
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ------------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Tcp/Ip communication link.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "xeTcpIpLink.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "xsProtocol.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deClock.h"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deInt32.h"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace xe
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyryenum
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SEND_BUFFER_BLOCK_SIZE		= 1024,
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SEND_BUFFER_NUM_BLOCKS		= 64
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Utilities for writing messages out.
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void writeMessageHeader (de::BlockBuffer<deUint8>& dst, xs::MessageType type, int messageSize)
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint8 hdr[xs::MESSAGE_HEADER_SIZE];
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	xs::Message::writeHeader(type, messageSize, &hdr[0], xs::MESSAGE_HEADER_SIZE);
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.write(xs::MESSAGE_HEADER_SIZE, &hdr[0]);
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void writeKeepalive (de::BlockBuffer<deUint8>& dst)
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	writeMessageHeader(dst, xs::MESSAGETYPE_KEEPALIVE, xs::MESSAGE_HEADER_SIZE);
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.flush();
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void writeExecuteBinary (de::BlockBuffer<deUint8>& dst, const char* name, const char* params, const char* workDir, const char* caseList)
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int		nameSize			= (int)strlen(name)		+ 1;
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int		paramsSize			= (int)strlen(params)	+ 1;
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int		workDirSize			= (int)strlen(workDir)	+ 1;
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int		caseListSize		= (int)strlen(caseList)	+ 1;
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int		totalSize			= xs::MESSAGE_HEADER_SIZE + nameSize + paramsSize + workDirSize + caseListSize;
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	writeMessageHeader(dst, xs::MESSAGETYPE_EXECUTE_BINARY, totalSize);
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.write(nameSize,		(const deUint8*)name);
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.write(paramsSize,	(const deUint8*)params);
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.write(workDirSize,	(const deUint8*)workDir);
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.write(caseListSize,	(const deUint8*)caseList);
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.flush();
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void writeStopExecution (de::BlockBuffer<deUint8>& dst)
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	writeMessageHeader(dst, xs::MESSAGETYPE_STOP_EXECUTION, xs::MESSAGE_HEADER_SIZE);
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	dst.flush();
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TcpIpLinkState
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
773c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpLinkState::TcpIpLinkState (CommLinkState initialState, const char* initialErr)
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_state					(initialState)
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_error					(initialErr)
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_lastKeepaliveReceived	(0)
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_stateChangedCallback	(DE_NULL)
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_testLogDataCallback		(DE_NULL)
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_infoLogDataCallback		(DE_NULL)
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_userPtr					(DE_NULL)
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
883c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpLinkState::~TcpIpLinkState (void)
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
923c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommLinkState TcpIpLinkState::getState (void) const
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::ScopedLock lock(m_lock);
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_state;
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
993c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommLinkState TcpIpLinkState::getState (std::string& error) const
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::ScopedLock lock(m_lock);
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	error = m_error;
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_state;
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLinkState::setCallbacks (CommLink::StateChangedFunc stateChangedCallback, CommLink::LogDataFunc testLogDataCallback, CommLink::LogDataFunc infoLogDataCallback, void* userPtr)
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::ScopedLock lock(m_lock);
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_stateChangedCallback		= stateChangedCallback;
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_testLogDataCallback		= testLogDataCallback;
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_infoLogDataCallback		= infoLogDataCallback;
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_userPtr					= userPtr;
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLinkState::setState (CommLinkState state, const char* error)
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CommLink::StateChangedFunc	callback	= DE_NULL;
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*						userPtr		= DE_NULL;
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::ScopedLock lock(m_lock);
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state = state;
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_error	= error;
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		callback	= m_stateChangedCallback;
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		userPtr		= m_userPtr;
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (callback)
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		callback(userPtr, state, error);
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
136745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryvoid TcpIpLinkState::onTestLogData (const deUint8* bytes, size_t numBytes) const
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CommLink::LogDataFunc	callback	= DE_NULL;
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*					userPtr		= DE_NULL;
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lock.lock();
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	callback	= m_testLogDataCallback;
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	userPtr		= m_userPtr;
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lock.unlock();
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (callback)
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		callback(userPtr, bytes, numBytes);
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
150745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryvoid TcpIpLinkState::onInfoLogData (const deUint8* bytes, size_t numBytes) const
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CommLink::LogDataFunc	callback	= DE_NULL;
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*					userPtr		= DE_NULL;
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lock.lock();
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	callback	= m_infoLogDataCallback;
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	userPtr		= m_userPtr;
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lock.unlock();
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (callback)
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		callback(userPtr, bytes, numBytes);
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLinkState::onKeepaliveReceived (void)
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::ScopedLock lock(m_lock);
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_lastKeepaliveReceived = deGetMicroseconds();
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1703c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeUint64 TcpIpLinkState::getLastKeepaliveRecevied (void) const
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::ScopedLock lock(m_lock);
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_lastKeepaliveReceived;
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TcpIpSendThread
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1783c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpSendThread::TcpIpSendThread (de::Socket& socket, TcpIpLinkState& state)
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_socket		(socket)
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_state		(state)
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_buffer		(SEND_BUFFER_BLOCK_SIZE, SEND_BUFFER_NUM_BLOCKS)
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_isRunning	(false)
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1863c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpSendThread::~TcpIpSendThread (void)
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpSendThread::start (void)
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!m_isRunning);
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Reset state.
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_buffer.clear();
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_isRunning = true;
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::Thread::start();
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpSendThread::run (void)
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint8 buf[SEND_BUFFER_BLOCK_SIZE];
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (!m_buffer.isCanceled())
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
209745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry			size_t			numToSend	= 0;
210745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry			size_t			numSent		= 0;
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deSocketResult	result		= DE_SOCKETRESULT_LAST;
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			try
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Wait for single byte and then try to read more.
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_buffer.read(1, &buf[0]);
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				numToSend = 1 + m_buffer.tryRead(DE_LENGTH_OF_ARRAY(buf)-1, &buf[1]);
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			catch (const de::BlockBuffer<deUint8>::CanceledException&)
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Handled in loop condition.
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			while (numSent < numToSend)
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				result = m_socket.send(&buf[numSent], numToSend-numSent, &numSent);
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (result == DE_SOCKETRESULT_CONNECTION_CLOSED)
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Connection closed");
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED)
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Connection terminated");
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_ERROR)
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Socket error");
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_WOULD_BLOCK)
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// \note Socket should not be in non-blocking mode.
237745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry					DE_ASSERT(numSent == 0);
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					deYield();
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(result == DE_SOCKETRESULT_SUCCESS);
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (const std::exception& e)
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_ERROR, e.what());
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpSendThread::stop (void)
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_isRunning)
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_buffer.cancel();
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		join();
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_isRunning = false;
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TcpIpRecvThread
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2633c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpRecvThread::TcpIpRecvThread (de::Socket& socket, TcpIpLinkState& state)
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_socket		(socket)
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_state		(state)
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_curMsgPos	(0)
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_isRunning	(false)
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2713c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpRecvThread::~TcpIpRecvThread (void)
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpRecvThread::start (void)
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!m_isRunning);
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Reset state.
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_curMsgPos = 0;
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_isRunning = true;
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::Thread::start();
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpRecvThread::run (void)
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (;;)
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool				hasHeader		= m_curMsgPos >= xs::MESSAGE_HEADER_SIZE;
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			bool				hasPayload		= false;
294745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry			size_t				messageSize		= 0;
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			xs::MessageType		messageType		= (xs::MessageType)0;
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (hasHeader)
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				xs::Message::parseHeader(&m_curMsgBuf[0], xs::MESSAGE_HEADER_SIZE, messageType, messageSize);
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				hasPayload = m_curMsgPos >= messageSize;
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (hasPayload)
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Process message.
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				handleMessage(messageType, m_curMsgPos > xs::MESSAGE_HEADER_SIZE ? &m_curMsgBuf[xs::MESSAGE_HEADER_SIZE] : DE_NULL, messageSize-xs::MESSAGE_HEADER_SIZE);
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_curMsgPos = 0;
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// Try to receive missing bytes.
312745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry				size_t				curSize			= hasHeader ? messageSize : (size_t)xs::MESSAGE_HEADER_SIZE;
313745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry				size_t				bytesToRecv		= curSize-m_curMsgPos;
314745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry				size_t				numRecv			= 0;
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deSocketResult		result			= DE_SOCKETRESULT_LAST;
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
317745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry				if (m_curMsgBuf.size() < curSize)
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_curMsgBuf.resize(curSize);
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				result = m_socket.receive(&m_curMsgBuf[m_curMsgPos], bytesToRecv, &numRecv);
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (result == DE_SOCKETRESULT_CONNECTION_CLOSED)
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Connection closed");
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED)
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Connection terminated");
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_ERROR)
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					XE_FAIL("Socket error");
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else if (result == DE_SOCKETRESULT_WOULD_BLOCK)
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// \note Socket should not be in non-blocking mode.
331745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry					DE_ASSERT(numRecv == 0);
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					deYield();
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(result == DE_SOCKETRESULT_SUCCESS);
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(numRecv <= bytesToRecv);
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_curMsgPos += numRecv;
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Continue receiving bytes / handle message in next iter.
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (const std::exception& e)
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_ERROR, e.what());
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpRecvThread::stop (void)
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_isRunning)
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Socket must be closed before terminating receive thread.
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		XE_CHECK(!m_socket.isReceiveOpen());
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		join();
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_isRunning = false;
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
362745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryvoid TcpIpRecvThread::handleMessage (xs::MessageType messageType, const deUint8* data, size_t dataSize)
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (messageType)
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_KEEPALIVE:
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_state.onKeepaliveReceived();
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_PROCESS_STARTED:
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			XE_CHECK_MSG(m_state.getState() == COMMLINKSTATE_TEST_PROCESS_LAUNCHING, "Unexpected PROCESS_STARTED message");
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_state.setState(COMMLINKSTATE_TEST_PROCESS_RUNNING);
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_PROCESS_LAUNCH_FAILED:
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			xs::ProcessLaunchFailedMessage msg(data, dataSize);
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			XE_CHECK_MSG(m_state.getState() == COMMLINKSTATE_TEST_PROCESS_LAUNCHING, "Unexpected PROCESS_LAUNCH_FAILED message");
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_state.setState(COMMLINKSTATE_TEST_PROCESS_LAUNCH_FAILED, msg.reason.c_str());
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_PROCESS_FINISHED:
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			XE_CHECK_MSG(m_state.getState() == COMMLINKSTATE_TEST_PROCESS_RUNNING, "Unexpected PROCESS_FINISHED message");
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			xs::ProcessFinishedMessage msg(data, dataSize);
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_state.setState(COMMLINKSTATE_TEST_PROCESS_FINISHED);
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_UNREF(msg); // \todo [2012-06-19 pyry] Report exit code.
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_PROCESS_LOG_DATA:
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case xs::MESSAGETYPE_INFO:
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Ignore leading \0 if such is present. \todo [2012-06-19 pyry] Improve protocol.
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (data[dataSize-1] == 0)
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				dataSize -= 1;
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (messageType == xs::MESSAGETYPE_PROCESS_LOG_DATA)
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				XE_CHECK_MSG(m_state.getState() == COMMLINKSTATE_TEST_PROCESS_RUNNING, "Unexpected PROCESS_LOG_DATA message");
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_state.onTestLogData(&data[0], dataSize);
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_state.onInfoLogData(&data[0], dataSize);
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			XE_FAIL("Unknown message");
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TcpIpLink
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4143c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpLink::TcpIpLink (void)
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_state			(COMMLINKSTATE_ERROR, "Not connected")
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_sendThread		(m_socket, m_state)
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_recvThread		(m_socket, m_state)
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_keepaliveTimer	(DE_NULL)
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_keepaliveTimer = deTimer_create(keepaliveTimerCallback, this);
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(m_keepaliveTimer);
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4243c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTcpIpLink::~TcpIpLink (void)
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		closeConnection();
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (...)
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Can't do much except to ignore error.
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimer_destroy(m_keepaliveTimer);
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::closeConnection (void)
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deSocketState state = m_socket.getState();
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (state != DE_SOCKETSTATE_DISCONNECTED && state != DE_SOCKETSTATE_CLOSED)
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			m_socket.shutdown();
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deTimer_isActive(m_keepaliveTimer))
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deTimer_disable(m_keepaliveTimer);
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_sendThread.isRunning())
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_sendThread.stop();
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_recvThread.isRunning())
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_recvThread.stop();
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_socket.getState() != DE_SOCKETSTATE_CLOSED)
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_socket.close();
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::connect (const de::SocketAddress& address)
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(m_socket.getState() == DE_SOCKETSTATE_CLOSED);
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(m_state.getState() == COMMLINKSTATE_ERROR);
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(!m_sendThread.isRunning());
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(!m_recvThread.isRunning());
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_socket.connect(address);
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Clear error and set state to ready.
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_READY, "");
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.onKeepaliveReceived();
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Launch threads.
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_sendThread.start();
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_recvThread.start();
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		XE_CHECK(deTimer_scheduleInterval(m_keepaliveTimer, xs::KEEPALIVE_SEND_INTERVAL));
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (const std::exception& e)
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		closeConnection();
4823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_ERROR, e.what());
483e16b0f52b4af5e934670dfc778cece6b3a4eb9b0Mika Isojärvi		throw;
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::disconnect (void)
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		closeConnection();
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_ERROR, "Not connected");
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (const std::exception& e)
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_ERROR, e.what());
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::reset (void)
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \note Just clears error state if we are connected.
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (m_socket.getState() == DE_SOCKETSTATE_CONNECTED)
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_state.setState(COMMLINKSTATE_READY, "");
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \todo [2012-07-10 pyry] Do we need to reset send/receive buffers?
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		disconnect(); // Abnormal state/usage. Disconnect socket.
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::keepaliveTimerCallback (void* ptr)
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TcpIpLink*	link			= static_cast<TcpIpLink*>(ptr);
5163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint64	lastKeepalive	= link->m_state.getLastKeepaliveRecevied();
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint64	curTime			= deGetMicroseconds();
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Check for timeout.
5203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if ((deInt64)curTime-(deInt64)lastKeepalive > xs::KEEPALIVE_TIMEOUT*1000)
5213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		link->m_state.setState(COMMLINKSTATE_ERROR, "Keepalive timeout");
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Enqueue new keepalive.
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		writeKeepalive(link->m_sendThread.getBuffer());
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (const de::BlockBuffer<deUint8>::CanceledException&)
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Ignore. Can happen in connection teardown.
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5343c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommLinkState TcpIpLink::getState (void) const
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_state.getState();
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5393c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommLinkState TcpIpLink::getState (std::string& message) const
5403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_state.getState(message);
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::setCallbacks (StateChangedFunc stateChangedCallback, LogDataFunc testLogDataCallback, LogDataFunc infoLogDataCallback, void* userPtr)
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_state.setCallbacks(stateChangedCallback, testLogDataCallback, infoLogDataCallback, userPtr);
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5493c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::startTestProcess (const char* name, const char* params, const char* workingDir, const char* caseList)
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(m_state.getState() == COMMLINKSTATE_READY);
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_state.setState(COMMLINKSTATE_TEST_PROCESS_LAUNCHING);
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	writeExecuteBinary(m_sendThread.getBuffer(), name, params, workingDir, caseList);
5553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TcpIpLink::stopTestProcess (void)
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	XE_CHECK(m_state.getState() != COMMLINKSTATE_ERROR);
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	writeStopExecution(m_sendThread.getBuffer());
5613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // xe
564