testexecmgmt/ucc/Source/SerialTcpRelay/CSerialTcpRelay.cpp
changeset 0 3da2a79470a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/Source/SerialTcpRelay/CSerialTcpRelay.cpp	Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,280 @@
+/*
+* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+* System Includes
+*
+*/
+
+
+
+#include <stdio.h>
+#include <assert.h>
+
+
+/*************************************************************************************
+ *
+ * LocalIncludes
+ *
+ ************************************************************************************/
+#include "CSerialTcpRelay.h"
+
+
+/*************************************************************************************
+ *
+ * Definitions
+ *
+ ************************************************************************************/
+#define SOCKET_TIMEOUT (1000)
+
+
+/*************************************************************************************
+ *
+ * PUBLIC METHOD: CSerialTcpRelay
+ *
+ ************************************************************************************/
+CSerialTcpRelay::CSerialTcpRelay() : iSerialThread("SerialThread"), iSocketThread("SocketThread")
+{
+	iSerialPort = NULL;
+	iSocket = INVALID_SOCKET;
+	iState = iSerialState = iSocketState = RS_NEW;
+}
+
+
+/*************************************************************************************
+ *
+ * PUBLIC METHOD: ~CSerialTcpRelay
+ *
+ ************************************************************************************/
+CSerialTcpRelay::~CSerialTcpRelay()
+{
+	assert( iSocket == INVALID_SOCKET );
+	assert( iState != RS_ACTIVE );
+	assert( iSerialState != RS_ACTIVE );
+	assert( iSocketState != RS_ACTIVE );
+}
+
+
+/*************************************************************************************
+ *
+ * PUBLIC METHOD: InitialiseRelay
+ *
+ ************************************************************************************/
+TRelayError CSerialTcpRelay::InitialiseRelay( CSerialPort *aSerialPort, SOCKADDR_IN aRemoteAddress, char *aInitialBuffer, int aBufferLength, int *aErrCode )
+{
+	int err;
+
+	// check params
+	assert( aSerialPort != NULL );
+	assert( aErrCode != NULL );
+
+	// save the state vars
+	*aErrCode = 0;
+	iSerialPort = aSerialPort;
+	iRemoteAddress = aRemoteAddress;
+
+	// open the socket
+	iSocket = socket( AF_INET, SOCK_STREAM, 0 );
+	if( iSocket == INVALID_SOCKET ){
+		*aErrCode = WSAGetLastError();
+		return RE_SOCKET_FAILED;
+	}
+	err = connect( iSocket, (struct sockaddr*)&iRemoteAddress, sizeof(iRemoteAddress) );
+	if( err == SOCKET_ERROR ) {
+		*aErrCode = WSAGetLastError();
+		closesocket( iSocket );
+		iSocket = INVALID_SOCKET;
+		return RE_CONNECT_FAILED;
+	}
+
+	// if there is some initial data then send it
+	if( (aInitialBuffer != NULL) && (aBufferLength > 0) ) {
+		err = send( iSocket, aInitialBuffer, aBufferLength, 0 );
+		if( err != aBufferLength ) {
+			*aErrCode = WSAGetLastError();
+			closesocket( iSocket );
+			iSocket = INVALID_SOCKET;
+			return RE_INITIAL_SEND_FAILED;
+		}
+	}
+
+	// update the state
+	iState = iSerialState = iSocketState = RS_ACTIVE;
+
+	// ok we are ready to go
+	return RE_SUCCESS;
+}
+
+
+/*************************************************************************************
+ *
+ * PUBLIC METHOD: ExecuteRelay
+ *
+ ************************************************************************************/
+TRelayError CSerialTcpRelay::ExecuteRelay()
+{
+	TThreadError terr;
+	int errcode;
+
+	// create the serial thread
+	terr = iSerialThread.StartThread( CSerialTcpRelay::SerialThreadProc, this, &errcode );
+	assert( terr == TE_NONE );
+
+	// create the socket thread
+	terr = iSocketThread.StartThread( CSerialTcpRelay::SocketThreadProc, this, &errcode );
+	assert( terr == TE_NONE );
+
+	// wait for the serial thread to exit
+	terr = iSerialThread.WaitForThread( INFINITE );
+	assert( terr == TE_NONE );
+
+	// wait for the socket thread to exit
+	terr = iSocketThread.WaitForThread( INFINITE );
+	assert( terr == TE_NONE );
+
+	// done
+	iState = RS_CLOSED;
+	return RE_SUCCESS;
+}
+
+
+/*************************************************************************************
+ *
+ * PRIVATE METHOD: ExecuteSerialThread
+ *
+ ************************************************************************************/
+TRelayError CSerialTcpRelay::ExecuteSerialThread()
+{
+	int err, bytes_read;
+	DWORD dwModemStatus;
+
+	// repeat...
+	while( 1 ) {
+
+		// read from the serial port
+		bytes_read = SERIALREADBUFFSIZE;
+		err = iSerialPort->ReceiveBytes( iSerialReadBuffer, &bytes_read );
+
+		// if there was an error other than timeout then break
+		if( err != 0 ) {
+			break;
+		}
+
+		// write any received data to the socket - break on error
+		if( bytes_read > 0 ) {
+//			fprintf( stderr, "DEBUG: serial <-> socket (%d)\n", bytes_read );
+			err = send( iSocket, iSerialReadBuffer, bytes_read, 0 );
+			if( err != bytes_read ) {
+				break;
+			}
+		}
+
+		// check the serial line flags - if the peer has lowered cts or dsr then
+		// we take this as meaning that they have closed the port
+		err = GetCommModemStatus( iSerialPort->Handle(), &dwModemStatus );
+		assert( err != 0 );
+		if( ((dwModemStatus & MS_CTS_ON) == 0) ) {
+			break;
+		}
+
+		// if the socket thread has exited then exit
+		if( iSocketState == RS_CLOSED ) {
+			break;
+		}
+	}
+		
+	// set my status to closed 
+	iSerialState = RS_CLOSED;
+	return RE_SUCCESS;
+}
+
+
+/*************************************************************************************
+ *
+ * PRIVATE METHOD: ExecuteSerialThread
+ *
+ ************************************************************************************/
+TRelayError CSerialTcpRelay::ExecuteSocketThread()
+{
+	int err, bytes_read, bytes_written;
+	struct timeval read_timeout;
+	fd_set read_fds;
+
+	// repeat...
+	while( 1 ) {
+
+		// setup things
+		read_timeout.tv_sec = 0;
+		read_timeout.tv_usec = (SOCKET_TIMEOUT*1000);
+		FD_ZERO( &read_fds );
+		FD_SET( iSocket, &read_fds );
+
+		// see if data is available
+		err = select( 1, &read_fds, NULL, NULL, &read_timeout );
+
+		// break on errors
+		if( err == SOCKET_ERROR ) {
+			break;
+		}
+
+		// if there is data available then read it - break on error
+		if( err != 0 ) {
+			bytes_read = recv( iSocket, iSocketReadBuffer, SOCKETREADBUFFSIZE, 0 );
+			if( bytes_read <= 0 ) {
+				break;
+			}
+		}
+
+		// write any received data to the serial port - break on error
+		if( bytes_read > 0 ) {
+			bytes_written = bytes_read;
+//			fprintf( stderr, "DEBUG: socket <-> serial (%d)\n", bytes_read );
+			err = iSerialPort->SendBytes( iSocketReadBuffer, &bytes_written );
+			if( err != 0 ) {
+				break;
+			}
+		}
+
+		// if the serial thread has exited then exit
+		if( iSerialState == RS_CLOSED ) {
+			break;
+		}
+
+	}
+	
+	// close the socket
+	closesocket( iSocket );
+	iSocket = INVALID_SOCKET;
+
+	// set my status to closed 
+	iSocketState = RS_CLOSED;
+	return RE_SUCCESS;
+}
+
+
+/*************************************************************************************
+ *
+ * PRIVATE METHOD: Thread Entry Procs
+ *
+ ************************************************************************************/
+int CSerialTcpRelay::SerialThreadProc( CSerialTcpRelay *aRelay )
+{
+	return (int)aRelay->ExecuteSerialThread();
+}
+
+
+int CSerialTcpRelay::SocketThreadProc( CSerialTcpRelay *aRelay )
+{
+	return (int)aRelay->ExecuteSocketThread();
+}
+