testexecmgmt/ucc/Source/MobileTermination/CUDPAirInterface.cpp
changeset 0 3da2a79470a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/Source/MobileTermination/CUDPAirInterface.cpp	Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,313 @@
+/*
+* 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 <memory.h>
+#include <assert.h>
+#ifndef WIN32
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+
+/*******************************************************************************
+ *
+ * Local Includes
+ *
+ ******************************************************************************/
+#include "CUDPAirInterface.h"
+
+
+/*******************************************************************************
+ *
+ * Definitions
+ *
+ ******************************************************************************/
+#ifndef WIN32
+#define SOCKET_ERROR        (-1)
+#define INVALID_SOCKET      (-1)
+#define ADDRESS_INTEGER     s_addr
+#define closesocket(x)     (shutdown(x,SHUT_RDWR),close(x))
+#else
+typedef int socklen_t;
+#endif
+
+
+/*******************************************************************************
+ *
+ * Macro Functions
+ *
+ ******************************************************************************/
+
+
+/*******************************************************************************
+ *
+ * Constructor - sets the passed pointers and sets the state to disabled
+ *
+ ******************************************************************************/
+CUDPAirInterface::CUDPAirInterface( TPhoneData *aPhoneData, CLog *aLog  )
+{
+	// verify parameters 
+	assert( aPhoneData != NULL );
+	assert( aLog != NULL );
+
+	// init state
+	iPhoneData = aPhoneData;
+	iProcessData = NULL;
+	iLog = aLog;
+	iFilter = NULL;
+	memset( &iRemoteAddress, 0, sizeof(iRemoteAddress) );
+	memset( &iLocalAddress, 0, sizeof(iLocalAddress) );
+	iSockIncoming = INVALID_SOCKET;
+	iSockOutgoing = INVALID_SOCKET;
+	iExitFlag = 0;
+	iRemoteAddressValid = 0;
+}
+
+CUDPAirInterface::~CUDPAirInterface( )
+{
+	// check the status of the sockets
+	assert( iSockIncoming == INVALID_SOCKET );
+	assert( iSockOutgoing == INVALID_SOCKET );
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: LISTEN-THREAD: ListenOnInterface. Binds to local port and 
+ * then starts listening on this port for more incoming data. Any incoming data
+ * is then sent to the datalink layer.
+ *
+ ******************************************************************************/
+TAirInterfaceError CUDPAirInterface::ListenOnInterface( int *aErrCode )
+{
+	TDataPathError derr;
+	int err, errcode;
+	struct sockaddr_in remote_recv_addr;
+	socklen_t addrlen;
+
+	// verify params
+	assert( aErrCode != NULL );
+	*aErrCode = 0;
+
+	// check that the local port is invalid
+	assert( iSockIncoming == INVALID_SOCKET );
+
+	// create the listening socket
+	iSockIncoming = socket( AF_INET, SOCK_DGRAM, 0 );
+	if( iSockIncoming == INVALID_SOCKET ) {
+		*aErrCode = GetSocketError();
+		return AIE_SOCKET_FAILED;
+	}
+
+	// if the exit flag is set then exit now
+	if( iExitFlag != 0 ) {
+	  closesocket( iSockIncoming );
+	  iSockIncoming = INVALID_SOCKET;
+	  return AIE_NONE;
+	}
+	
+
+	// bind the listening socket -- bind to an ephemeral port
+	iLocalAddress.sin_family = AF_INET;
+	iLocalAddress.sin_port = htons(0);
+	iLocalAddress.sin_addr.ADDRESS_INTEGER = INADDR_ANY;
+	err = bind( iSockIncoming, (struct sockaddr*)&iLocalAddress, sizeof(iLocalAddress) );
+
+	// get the allocated port info
+	addrlen = sizeof(iLocalAddress);
+	err = getsockname( iSockIncoming, (sockaddr*)&iLocalAddress, &addrlen );
+	assert( err == 0 );
+
+	// check for errors during the bind
+	if( err != 0 ) {
+	  closesocket( iSockIncoming );
+	  iSockIncoming = INVALID_SOCKET;
+	  *aErrCode = GetSocketError();
+	  return AIE_BIND_FAILED;
+	}
+
+	// use the listening socket as the outgoing socket -- no reason we can't do 
+	// this. It also means that we know the source port of the outgoing datagrams 
+	// and hence we can do some proper NISTNET stuff
+	iSockOutgoing = iSockIncoming;
+	
+	// read from the socket until an error occurs (this may be induced by another
+	// thread closing the socket)
+	while( 1 ) {
+		
+		// now read from the socket
+		memset( &remote_recv_addr, 0, sizeof(remote_recv_addr) );
+		addrlen = sizeof(remote_recv_addr);
+		err = recvfrom( iSockIncoming, iPacketBuffer, KPCKTBUFFSIZE, 0, (struct sockaddr*)&remote_recv_addr, &addrlen );
+
+		// check for errors
+		if( err == SOCKET_ERROR ) {
+		  closesocket( iSockIncoming );
+		  iSockIncoming = iSockOutgoing = INVALID_SOCKET;
+		  *aErrCode = GetSocketError();
+		  return AIE_RECEIVE_FAILED;
+		}
+
+		// send the data to the filters
+		if( iFilter != NULL ) {
+			iFilter->ProcessIncomingData( iPacketBuffer, err );
+		}
+
+		// otherwise we have data to send to the datalink layer
+		derr = iProcessData->ProcessUUData( iPacketBuffer, err, &errcode );
+		if( derr != DPE_NONE ) {	
+			iLog->WriteLogEntry( SV_WARNING, "CUDPAirInterface::ListenOnInterface", "ProcessUUData returned", derr, errcode );
+		}
+	}
+
+	// code should never get here
+	assert( !"INVALID CODE PATH" );
+	return AIE_NONE;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: MAIN-THREAD: StopInterface. Closes the socket (if it is open)
+ * was called. We can't guarantee when the receiving thread will return. But it
+ * must before any other calls can be made.
+ *
+ ******************************************************************************/
+int CUDPAirInterface::StopInterface()
+{
+	// set the exit flag
+	iExitFlag = 1;
+
+	// close the socket if it is open
+	if( iSockIncoming != INVALID_SOCKET ) {
+	  closesocket( iSockIncoming );
+	  iSockIncoming = iSockOutgoing = INVALID_SOCKET;
+	}
+
+	// done 
+	return 0;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: GetLocalAddress 
+ *
+ ******************************************************************************/
+void CUDPAirInterface::GetLocalAddress( struct sockaddr_in *aLocalAddress )
+{
+	assert( aLocalAddress != NULL );
+	*aLocalAddress = iLocalAddress;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: SetRemoteAddress
+ *
+ ******************************************************************************/
+void CUDPAirInterface::GetRemoteAddress( struct sockaddr_in *aRemoteAddress )
+{
+	*aRemoteAddress = iRemoteAddress;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: SetRemoteAddress
+ *
+ ******************************************************************************/
+void CUDPAirInterface::SetRemoteAddress( struct sockaddr_in aRemoteAddress )
+{
+	iRemoteAddressValid = 1;
+	iRemoteAddress = aRemoteAddress;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: SetDatalink
+ *
+ ******************************************************************************/
+void CUDPAirInterface::SetDatalink( IProcessData *aProcessData )
+{
+	iProcessData = aProcessData;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD. SetFilter, called by the main setup call in 
+ * cphone - links up all the bits.
+ *
+ ******************************************************************************/
+void CUDPAirInterface::SetFilter( IFilter *aFilter )
+{
+	iFilter = aFilter;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: TE-THREAD: SendPacket, when data is received on the te 
+ * channel it eventually makes its way here (in its thread) to send the 
+ * data out the uu interface.
+ *
+ ******************************************************************************/
+TDataPathError CUDPAirInterface::SendPacket( char *data, int len, int *aErrCode )
+{
+	int err;
+
+	//verify the params
+	assert( data != NULL );
+	assert( aErrCode != NULL );
+	*aErrCode = 0;
+
+	// make sure the remote address is set - not an error
+	if( iRemoteAddressValid == 0 ) {
+		return DPE_NONE;
+	}
+
+	// send the packet - send in 4k chunks to avoid system defined UDP packet size limit
+	err = sendto( iSockOutgoing, data, len, 0, (struct sockaddr*)&iRemoteAddress, sizeof(iRemoteAddress) );
+	if( err == SOCKET_ERROR ) {
+		*aErrCode = GetSocketError();
+		return DPE_SEND_FAILED;
+	}
+	
+	// done
+	return DPE_NONE;
+}
+
+
+/*******************************************************************************
+ *
+ * PRIVATE METHODS: Helper functions
+ *
+ ******************************************************************************/
+int CUDPAirInterface::GetSocketError()
+{
+#ifdef WIN32
+	return WSAGetLastError();
+#else
+	return errno;
+#endif
+}