testexecmgmt/ucc/Source/MobileTermination/CTCPTEChannel.cpp
changeset 0 3da2a79470a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/Source/MobileTermination/CTCPTEChannel.cpp	Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,283 @@
+/*
+* 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>
+#ifndef WIN32
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+
+/*******************************************************************************
+ *
+ * Local Includes
+ *
+ ******************************************************************************/
+#include "CTCPTEChannel.h"
+
+
+/*******************************************************************************
+ *
+ * Definitions
+ *
+ ******************************************************************************/
+#ifndef WIN32
+#define SOCKET_ERROR (-1)
+#define INVALID_SOCKET (-1)
+#define Sleep(x) sleep(x/1000)
+#else
+#define SHUT_RDWR SD_BOTH
+#endif
+
+
+/*******************************************************************************
+ *
+ * Macro Functions
+ *
+ ******************************************************************************/
+#ifndef WIN32
+#define closesocket(x) (shutdown(x,SHUT_RDWR),close(x))
+#endif
+
+
+/*******************************************************************************
+ *
+ * Constructor -- initialise all state
+ *
+ ******************************************************************************/
+CTcpTeChannel::CTcpTeChannel( TPhoneData *aPhoneData, CLog *aLog )
+{
+	// verify args
+	assert( aPhoneData != NULL );
+	assert( aLog != NULL );
+
+	// initialise state
+	iPhoneData = aPhoneData;
+	iDatalink = NULL;
+	iFilter = NULL;
+	iLog = aLog;
+	iSock = INVALID_SOCKET;
+	iStreamBuffer[0] = 0;
+	iExitFlag = 0;
+	iSocketSetFlag = 0;
+}
+
+CTcpTeChannel::~CTcpTeChannel()
+{
+	assert( iSock == INVALID_SOCKET );
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD. SetDatalink, called by the main setup call in 
+ * cphone - links up all the bits.
+ *
+ ******************************************************************************/
+void CTcpTeChannel::SetDatalink( IProcessData *aDatalink )
+{
+	iDatalink = aDatalink;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD. SetFilter, called by the main setup call in 
+ * cphone - links up all the bits.
+ *
+ ******************************************************************************/
+void CTcpTeChannel::SetFilter( IFilter *aFilter )
+{
+	iFilter = aFilter;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: SERVER-THREAD: 
+ *
+ ******************************************************************************/
+TChannelError CTcpTeChannel::SetSocket( int aSocket )
+{
+	// check that the socket is sane
+	assert( aSocket >= 0 );
+
+	// check that we haven't already set if
+	if( iSocketSetFlag != 0 ) {
+		return CE_SOCKET_ALREADY_SET;
+	}
+
+	// ok - set the socket
+	iSock = aSocket;
+	iSocketSetFlag = 1;
+	return CE_NONE;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: LISTEN-THREAD: ListenOnChannel. This is the entry point for 
+ * the listening thread. It sits in the loop below and passes all received data 
+ * to the datalink layer. 
+ *
+ ******************************************************************************/
+TChannelError CTcpTeChannel::ListenOnChannel( int *aErrCode )
+{
+	TDataPathError derr;
+	int err;
+	int errcode;
+
+	// check the params
+	assert( aErrCode != NULL );
+	*aErrCode = 0;
+
+	// listen on the socket until it closes
+	while( 1 ) {
+
+		// if the socket is not defined then just wait for it
+		if( iSock == INVALID_SOCKET ) {
+			Sleep( 1000 );
+			if( iExitFlag != 0 ) {
+				return CE_NONE;
+			}
+			continue;
+		}
+
+		// read from socket if it is defined
+		err = recv( iSock, iStreamBuffer, KBUFFSIZE, 0 );
+
+		// if the socket has been closed then cleanup and return
+		if( err == 0 ) {
+		  closesocket( iSock );
+		  iSock = INVALID_SOCKET;
+		  return CE_NONE;
+		}
+
+		// if an error has occured then report it and cleanup
+		if( err == SOCKET_ERROR ) {
+			*aErrCode = GetSocketError();
+			closesocket( iSock );
+			iSock = INVALID_SOCKET;
+			return CE_RECEIVE_FAILED;
+		}
+
+		// pass the data received through the filters. 
+		// : the control flow below allows the filter to analyse the data, and also change 
+		// the data in-place. However, it doesn't allow the interface to change the size of the 
+		// data (limiting the modifications it can make). This isn't a problem now since no 
+		// filters do this -- but when this is needed it should be implemented here, and in the same
+		// place in the uu interface.
+		if( iFilter != NULL ) {
+			iFilter->ProcessOutgoingData( iStreamBuffer, err );
+		}
+
+		// Now pass the data through to the datalink layer. A datalink layer MUST be
+		// defined if the socket is defined.
+		assert( iDatalink != NULL );
+		derr = iDatalink->ProcessTEData( iStreamBuffer, err, &errcode );
+		if( derr != DPE_NONE ) {	
+			iLog->WriteLogEntry( SV_WARNING, "CTcpTeChannel::ListenOnChannel", "ProcessTEData returned error", derr, errcode );
+		}
+	}
+
+	// should never get here
+	assert( !"INVALID CODE PATH" );
+	return CE_NONE;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: MAIN-THREAD: StopChannel. This closes the socket (if open) 
+ * which will force the recv to return 0 and the listen-thread will return. It
+ * also sets the exit flag for when we want to stop the channel before it 
+ * really even started (poor thing).
+ *
+ ******************************************************************************/
+void CTcpTeChannel::StopChannel()
+{
+	// close the socket
+	if( iSock != INVALID_SOCKET ) {
+	  closesocket( iSock );
+	  iSock = INVALID_SOCKET;
+	}
+
+	// set the exit flag
+	iExitFlag = 1;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: AIR INTERFACE THREAD: SendPacket. This is called by the data
+ * link layer when it receives some data from the air interface that it now
+ * decides to forward on.
+ *
+ ******************************************************************************/
+TDataPathError CTcpTeChannel::SendPacket( char *data, int len, int *aErrCode )
+{
+	int err;
+	int bytes_to_send;
+	int bytes_sent;
+
+	// check params
+	assert( aErrCode != NULL );
+	*aErrCode = 0;
+
+	// if there is no connection then return. This is not unexpected or bad so
+	// no error is returned.
+	if( iSock == INVALID_SOCKET ) {
+		return DPE_NONE;
+	}
+
+	// otherwise send data
+	bytes_to_send = len;
+	bytes_sent = 0;
+	while( bytes_sent < bytes_to_send ) {
+		err = send( iSock, &(data[bytes_sent]), bytes_to_send - bytes_sent, 0 );
+		if( err == -1 ) {
+			*aErrCode = GetSocketError();
+			closesocket( iSock );
+			iSock = INVALID_SOCKET;
+			iSocketSetFlag = 0;
+			return DPE_SEND_FAILED;
+		}
+		bytes_sent += err;
+	}
+
+	// success
+	return DPE_NONE;
+}
+
+
+/*******************************************************************************
+ *
+ * PRIVATE METHODS: HELPER FUNCTIONS
+ *
+ ******************************************************************************/
+int CTcpTeChannel::GetSocketError()
+{
+#ifdef WIN32
+  return WSAGetLastError();
+#else
+  return errno;
+#endif
+}