diff -r 000000000000 -r af10295192d8 linklayerprotocols/ethernetnif/IRLAN/IRLANCTL.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linklayerprotocols/ethernetnif/IRLAN/IRLANCTL.CPP Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,1017 @@ +// Copyright (c) 1997-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: +// Irlan connection control engine +// +// + +/** + @file +*/ + +#include +#include +#include +#include +#include +#include +#include "PKTDRV.H" +#include "ETHINTER.H" +#include "IRLAN.H" +#include "IRLANUTL.H" +#include "INTSOCK.H" +#include "IRLANBUF.H" +#include "IRLANDAT.H" +#include "irlantimer.h" + +//#define __TRACEWIN__ +#ifdef __TRACEWIN__ + #include +#else + #define LOG(a) +#endif + +/** +Create a new CIrlanControlEngine object. +@param aPktDrv A pointer to CIrlanPktDrv object. +@return A pointer to CIrlanControlEngine object. +*/ +CIrlanControlEngine *CIrlanControlEngine::NewL(CIrlanPktDrv* aPktDrv) +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CIrlanControlEngine::NewL\r\n"))); +#endif + CIrlanControlEngine *cc=new (ELeave) CIrlanControlEngine; + CleanupStack::PushL(cc); + cc->ConstructL(aPktDrv); + CActiveScheduler::Add(cc); + CleanupStack::Pop(); + return cc; +} + +/** +Think this should be a deferred deletion here especially +if IrLAN is already connected. +Destructor. +*/ +CIrlanControlEngine::~CIrlanControlEngine() +{ + LOG(Log::Printf(_L("IRLAN ~CIrlanControlEngine\r\n"))); + CIrlanParameter *par; + TDblQueIter i(iIrlanParameterList); + while (par=i++,par!=NULL) + { + par->iLink.Deque(); + delete par; + } + iDataSendQ.Free(); + + if (iTimers) + iTimers->StopIrlanControlEngineTimer(); + delete iTimers; + if (iSender) + { + iSender->Cancel(); + delete iSender; + } + if (iReceiver) + { + iReceiver->Cancel(); + delete iReceiver; + } + delete iHostResolver; // do close on this too? + delete iNetDatabase; // do close on this too? + if (iDataSock) + iDataSock->Close(); + if (iControlSock) + iControlSock->Close(); + + delete iRecvBuffer; + CActive::Cancel(); +} + +/** +Default constructor +*/ +CIrlanControlEngine::CIrlanControlEngine() + :CActive(EIrlanControlPriority) + ,iRecvBufPtr(NULL,0) +{ +} + +/** +The CIrlanControlEngine::ConstructL performs all the memory allocating initialisations. +@param aNotify A pointer to CIrlanPktDrv object. +*/ +void CIrlanControlEngine::ConstructL(CIrlanPktDrv* aNotify) +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CIrlanControlEngine::ConstructL\r\n"))); +#endif + iRecvBufLength=KIrlanBufSize; + iTimers=CIrlanControlEngineTimers::NewL(this); + iRecvBuffer=HBufC8::NewMaxL(iRecvBufLength); + TPtr8 temp=iRecvBuffer->Des(); + iRecvBufPtr.Set(temp); + iNotify=aNotify; + iIrlanParameterList.SetOffset(_FOFF(CIrlanParameter,iLink)); +} + +/** +Handles Errors. +*/ +void CIrlanControlEngine::HandleErrorL() +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Error in CIrlanControlEngine::RunL\r\n"))); +#endif + switch (iState) + { + case E_Idle: + case E_Query: + case E_Conn: + PassiveIdleTransitionL(); + iState=E_PassiveIdle; + iDiscoveredDevice=0; + break; + case E_Data: + { + iState=E_Idle; + iDiscoveredDevice=0; + TPtr8 dest(&iHWAddr[0],6,6); + dest.FillZ(6); + // Tear down the link stuff. + delete iSender; + iSender=0; + delete iReceiver; + iReceiver=0; + break; + } + default: + break; + } +} + +/** +Irlan state machine - on hitting this RunL, either iStatus is KErrNone in which case +we have completed OK and can try the next stage or it isn't in which case we must +handle the error appropriately. The state machine is only rearmed if the phase action +produces some error. Otherwise, it is left up to the IrDA PRT to call back via the +socket/hostresolver/netDB notifer and for the request to be completed that way. +*/ +void CIrlanControlEngine::RunL() +{ +#ifdef __TRACEWIN__ + PrintState(); +#endif + RMBufChain pkt; + TInt ret=KErrNone; + if (iStatus!=KErrNone) + { + HandleErrorL(); + return; + } + switch (iState) + { + case E_Idle: + if (iDiscoveredDevice) + {// An IrDA discovery has been successfully completed. +// iHostResolver.Close(); + TRAP(ret,QueryRemoteIASL()); + User::LeaveIfError(ret); + iState=E_Query; + break; + } + ret=AttemptingDiscoveryL(); + // a KErrNone here indicates we're doing a discovery... + // any other error will be picked up as a PassiveIdleTransition + break; + case E_PassiveIdle: + // the remote side has successfully connected to us + // now we wait on receipt of remote command frames + QueueWaitForControlCommand(); + iState=E_Info; + break; + case E_Query: + // A query on remote device's IAS has successfully completed. + iOpenRetries=0; + ret=ConnectToProviderL(); + iState=E_Conn; + break; + case E_Conn: + // Completed OK - send the GetInfoCmd + ret=GetInfoCmd(); + iState=E_Info; + break; + case E_Info: + // Need to parse response from this query if it comes. + switch (iAccessType) + { + case EAccessPoint: + if (iAwaitingResponse) + { + ParseInfoReply(); + ret=GetMediaCmd(); + iState=E_Media; + break; + } + QueueWaitForControlResponse(); + break; + case EPeerToPeer: + if (iAwaitingCommand) + { + ParseControlCommand(); // also sends the reply + break; + } + QueueWaitForControlCommand(); + break; + case EHosted: + break; + } + break; + case E_Media: + if (iAwaitingResponse) + { + ret=ParseMediaReply(); + User::LeaveIfError(ret); + ret=OpenDataCmd(); + iState=E_Open; + break; + } + QueueWaitForControlResponse(); + break; + case E_Open: + if (iAwaitingResponse) + { + ParseOpenDataReply(); + // WE'RE ONLY SUPPORTING ACCESS MODE IRLAN AT PRESENT + __ASSERT_DEBUG(iAccessType==EAccessPoint,IrlanUtil::Fault(EIrlanInvalidIrlanMode)); + ret=GetDirectedFilterConfigCmd(); + iState=E_FilterConfig; + break; + } + QueueWaitForControlResponse(); + break; + case E_FilterConfig: + // This is an extra state I've added to handle filter config stuff + if (iAwaitingResponse) + { + ParseDirectedFilterConfigReply(); + ret=SetDirectedFilterOperationCmd(); + iState=E_FilterOperation; + break; + } + QueueWaitForControlResponse(); + break; + case E_FilterOperation: + // This is an extra state I've added to handle filter operation stuff + if (iAwaitingResponse) + { + ParseDirectedFilterOperationReply(); + ret=SetBroadcastFilterOperationCmd(); + iState=E_FilterBroadcast; + break; + } + QueueWaitForControlResponse(); + break; + case E_FilterBroadcast: + // This is an extra state I've added to handle broadcast filter stuff + if (iAwaitingResponse) + { + ParseBroadcastFilterOperationReply(); + ConnectToDataChannelL(); + break; + } + QueueWaitForControlResponse(); + break; + case E_Wait: + // Only needed if acting as a provd. + break; + case E_Arb: + // Only needed if acting as a provd. + break; + case E_Data: + // Once we're here, we can send/receive ethernet packets as data over IrLAN. + iSender=CIrlanSender::NewL(this,iDataSock); + iReceiver=CIrlanReceiver::NewL(this,iDataSock); + iReceiver->QueueRead(); + if (iDataSendQ.Remove(pkt)) + { + iSender->QueueSend(pkt); + pkt.Free(); + } + iNotify->LinkLayerUp(); //bring up the tcpip stack ect. + return; + case E_Close: + + break; + case E_Sync: + break; + default: + IrlanUtil::Panic(EIrlanErrorState); + break; + } + if (ret!=KErrNone) + ActivateStateMachine(ret); +} + + +/** +Process the packet received from the LinkLayer. +*/ +void CIrlanControlEngine::ProcessReceivedPacketL() +{ + RMBufPacket pkt; + + pkt.CreateL(iRecvBufPtr,0); + pkt.Pack(); + iNotify->Process(pkt); // We had a read queued and that has completed +} + + +/** +Starts up the state machine in E_Idle state - will lead to a discovery attempt. +*/ +void CIrlanControlEngine::StartL() +{ + TInt ret; + iHostResolver=CInternalHostResolver::NewL(); + if ((ret=iHostResolver->OpenL(_L("IrTinyTP"),this))!=KErrNone) + { + LOG(Log::Printf(_L("IRLAN CInternalHostResolver::OpenL failed with err=%d\r\n"),ret)); + User::Leave(ret); + } + iState=E_Idle; + iProtocol=iHostResolver->iProtocol; + ActivateStateMachine(); +} + +/** +cancellation of an outstanding request. +*/ +void CIrlanControlEngine::DoCancel() +{ + switch (iState) + { + case E_Data: + iSender->DoCancel(); + iReceiver->DoCancel(); + break; + default: + break; + } +} + +/** +Protocol inspects return +It blocks sending if it receives a return <= 0 +This value should be propogated up through the stack +@internalComponent +*/ +const TInt KStopSending = 0; + +/** +Protocol inspects return to indicate Keep sending the data. +@internalComponent +*/ +const TInt KContinueSending = 1; + +/** +Sender Class is generic and does not want to know about RMBuf's +Copy to a Heap Buffer and Free the packet. EtherII MAC layer comments +Say we should free the packet buffer +RMBuf could contain a chain so get into a contiguous buffer +@param aPdu A reference to the packet to be sent (really an RMBufPkt) +@param aSource A pointer to the source protocol. +@return 0 Tells the higher layer to stop sending the data. + 1 Tells higher layer that it can continue sending more data. +*/ +TInt CIrlanControlEngine::Send(RMBufChain& aPdu, TAny*) +{ + if (iState!=E_Data) + {// Not ready to send the packet. + aPdu.Free(); + return KStopSending; + } + // Need to stick the packet in a queue and kick the sender... + iDataSendQ.Append(aPdu); + iSender->KickSender(); + return KContinueSending; +} + + +/** +This kicks off the state machine active object. Completion in RunL.. +@param aStat The active object Request complete status. +*/ +void CIrlanControlEngine::ActivateStateMachine(TInt aStat) +{ + TRequestStatus *pS=&iStatus; + User::RequestComplete(pS,aStat); + SetActive(); +} + +//*************************** NOTIFIERS ********************************** + +/** +Upcall from SAP - more data arrived +Indicates that new data is available on a service access point +*/ +void CIrlanControlEngine::NewData(TUint /*aCount*/) +{ +} + +/** +Upcall from SAP - flow control on +Indicates that new buffer space is available on a service +*/ +void CIrlanControlEngine::CanSend() +{ + if (iState==E_Data) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CanSend received from SAP\r\n"))); +#endif + // if there's any data in the queue, force send it! + if (!iDataSendQ.IsEmpty()) + iSender->KickSender(); + return; + } +} + +/** +This returns the hardware address pulled out of response to +IrLAN FILTER_OPERATION/DYNAMIC request. +@return NULL Failure. + (NULL Terminated Binary String) The Hardware Address of the interface. LAN Device + Specific +@note this will not contain the correct MAC address until IRLAN recives a control frame. +*/ +TUint8* CIrlanControlEngine::GetInterfaceAddress() +{ + return &iHWAddr[0]; +} + +/** +Upcall from SAP. Notify layer above +Indicates that a connection attempt has completed successfully +*/ +void CIrlanControlEngine::ConnectComplete() +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect complete 1\r\n"))); +#endif + ActivateStateMachine(); +} + +#pragma warning (disable:4100) +/** +Upcall from SAP. Notify layer above +Indicates that a connection attempt has completed successfully +@param aConnectData Connect data (if supported) +*/ +void CIrlanControlEngine::ConnectComplete(const TDesC8& /*aConnectData*/) +{ + PrintState(); + TInt ret=KErrNone; + switch (iState) + { + case E_Conn: + // Successful completion of control channel connect. +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length())); +#endif + break; + case E_FilterBroadcast: + // Successful completion of data channel connect. +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length())); +#endif + iState=E_Data; // READY TO TRY AND SEND/RECEIVE PACKETS! + break; + default: + ret=KErrNotSupported; + break; + } + ActivateStateMachine(ret); +} +#pragma warning (default:4100) + +/** +Upcall from SAP. Notify layer above +Indicates that a connection attempt has completed successfully +@param aSSP The new SSP for passive opens +*/ +void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP) +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect complete 3 - not supported!!\r\n"))); +#endif + iAcceptControlSock=CInternalSocket::NewL(&aSSP,this); + ActivateStateMachine(); +} + +/** +Upcall from SAP. Notify layer above +Indicates that a connection attempt has completed successfully +@param aSSP The new SSP for passive opens +@param aConnectData Connect data (if supported) +*/ +void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP, + const TDesC8& /*aConnectData*/) +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect complete on accept socket\r\n"))); +#endif + iAcceptControlSock=CInternalSocket::NewL(&aSSP,this); + ActivateStateMachine(); +} + +/** +Upcall from SAP. Notify layer above. +Indicates that the SAP has finished closing down +@param aDelete Delete SAP +*/ +void CIrlanControlEngine::CanClose(TDelete /*aDelete*/) +{ +} + +/** +Upcall from SAP. Notify layer above. +Indicates that the SAP has finished closing down +@param aDisconnectData Any user data carried on the disconnect frame +@param aDelete Delete SAP +*/ +void CIrlanControlEngine::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/) +{ +} + +/** +Upcall from SAP - Error notification. +@param aError The error code +@param anOperationMask A bitmask of TOperationBitmasks values specifying which pending operations are + affected by the Error up-call +*/ +void CIrlanControlEngine::Error(TInt /*anError*/,TUint /*anOperationMask*/) +{ +} + +/** +Upcall from SAP - Not supported +Indicates that the other end of a connection has disconnected. +*/ +void CIrlanControlEngine::Disconnect(void) +{ +} + +/** +Indicates that the other end of a connection has disconnected + +@param aDisconnectData User data in the disconnect frame. +*/ +void CIrlanControlEngine::Disconnect(TDesC8& /*aDisconnectData*/) +{ +} + +/** +Upcall from SAP. Notify layer above +Indicates that the currently pending Ioctl has completed +@param aBuf Any data requested by the Ioctl operation. +*/ +void CIrlanControlEngine::IoctlComplete(TDesC8 * /*aBuf*/) +{ +} + +void CIrlanControlEngine::NoBearer(const TDesC8& /*aConnectionParams*/) +{ +} + +void CIrlanControlEngine::Bearer(const TDesC8& /*aConnectionInfo*/) +{ +} + +/** +Depending on error AND STATE!!, need to take corresponding action. +Notifier call back from IrDA PRT +This is where the request completes - it has already filled +in the name record passed through to GetByName so leave that. +@param aErr Error code. +*/ +void CIrlanControlEngine::QueryComplete(TInt aError) +{ + PrintState(); + switch (iState) + { + case E_Idle: + if (aError==KErrNone) // Successful discovery + {// iLog already filled in - pull out the device. + TIrdaSockAddr addr(iLog().iAddr); + // Check it has IrLAN set in it's discovery hint bits. + iDiscoveredDevice=addr.GetRemoteDevAddr(); +#ifdef __TRACEWIN__ + TUint numHintBytes=addr.GetServiceHintByteCount(); + TUint8 hintByte1=addr.GetFirstServiceHintByte(); + LOG(Log::Printf(_L("IRLAN !!!!!!!!!!!!! SUCCESSFUL DISCOVERY !!!!!!!!!!!!!!!\r\n"))); + LOG(Log::Printf(_L("IRLAN Remote machine dev addr=0x%08x\r\n"),iDiscoveredDevice)); + LOG(Log::Printf(_L("IRLAN Remote no. of service hint bytes is %d\r\n"),numHintBytes)); + LOG(Log::Printf(_L("IRLAN Remote first service hint byte is 0x%02x\r\n"),hintByte1)); + if (numHintBytes>1) + { + LOG(Log::Printf(_L("IRLAN Remote second service hint byte is 0x%02x\r\n"), + addr.GetSecondServiceHintByte())); + } + LOG(Log::Printf(_L("IRLAN Remote machine name is \"%s\"\r\n"),iLog().iName.PtrZ())); +#endif + } + else // Nothing discovered + aError=KErrNone; // This will ensure continued attempts. + break; + case E_Query: + if (aError==KErrNone) + {// IAS QUERY COMPLETED SUCCESSFULLY. + iResults.Copy(iQuery); + PrintIASResults(); + if (iResults.Type()==EIASDataInteger) + { + aError=iResults.GetInteger(iIrlanControlPortNum); + } + } + else + {// IAS QUERY COMPLETED UNSUCCESSFULLY. + PrintIASError(aError); + // Need to take corrective action!! (Done in HandleErrorL). + } + break; + default: + break; + } + ActivateStateMachine(aError); // Kick off state machine again. +} + +//********************** IRLAN STATE MACHINE ACTIONS ************************ + +TInt CIrlanControlEngine::PassiveIdleTransitionL() +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN PASSIVE IDLE STATE TRANSITION\r\n"))); +#endif + // first - queue the IAS db entry. + TIASDatabaseEntry iasentry; + if (!iNetDatabase) + { + iNetDatabase=CInternalNetDB::NewL(); + User::LeaveIfError(iNetDatabase->OpenL(TINYTP_PROTOCOL,this)); + } + iasentry.SetClassName(IRLAN_CLASSNAME); + iasentry.SetAttributeName(TINYTP_ATTRNAME); + iasentry.SetToInteger(9); + iNetDatabase->Add(iasentry); +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IrLAN PEER service registered on port 9\r\n"))); +#endif + + iListenSock=new (ELeave) CInternalSocket(); + User::LeaveIfError(iListenSock->OpenL(TINYTP_PROTOCOL,this)); + TIrdaSockAddr addr(iLog().iAddr); + addr.SetPort(0x09); // This is where IrLAN PEER is. + iListenSock->SetLocalName(addr); + iListenSock->WaitForConnect(2); + + iAccessType=EPeerToPeer; + /* + ret=iAcceptor->Open(); + sock1.Accept(sock2,iStatus); // the order of this accept call has changed in esock + User::WaitForRequest(stat3); + // second - do a listen and accept on corresponding port. + */ + + return KErrNone; +} + +TInt CIrlanControlEngine::AttemptingDiscoveryL() +{ +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN ATTEMPTING DISCOVERY\r\n"))); +#endif + if (!iDiscoveryAttempts) + { + iLog().iName=_S("*"); + iDiscoveryAttempts++; + TInt ret=iHostResolver->GetByName(iLog()); + return ret; + } + else + { + if (iDiscoveryAttempts>=5) + {// need to drop into passive idle state + return KErrNotFound; + } + // 1 sec between discoveries + TCallBack callback(CIrlanControlEngine::IrlanControlEngineTimerExpired,this); + iTimers->StartIrlanControlEngineTimer(callback,1000000L); + } + return KErrNone; // don't want to reactivate state machine +} + +TInt CIrlanControlEngine::IrlanControlEngineTimerExpired(TAny *aIrlan) +{ + CIrlanControlEngine *cc=(CIrlanControlEngine *)aIrlan; + switch (cc->iState) + { + case E_Idle: + // discovery timer has completed. try a discovery. + cc->iTimers->DoIrlanControlEngineTimerExpired(); + cc->iDiscoveryAttempts++; + cc->iHostResolver->GetByName(cc->iLog()); + break; + default: + break; + } + return 0; +} + +/** +Need to find out if the remote supports IrLAN. Note that this will involve +kicking up the IrLAP/IAS connections. Requires opening up a net database. +@return TRUE if the Classname, AttributeType and the Device is present otherwise some error code. +*/ +TInt CIrlanControlEngine::QueryRemoteIASL() +{ + TInt ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN QUERY REMOTE IAS\r\n"))); +#endif + TRAP(ret,iNetDatabase=CInternalNetDB::NewL()); + User::LeaveIfError(ret); + if ((ret=iNetDatabase->OpenL(TINYTP_PROTOCOL,this))!=KErrNone) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CInternalNetDB::OpenL failed with err=%d\r\n"),ret)); +#endif + User::Leave(ret); + } + return DoIASQuery(IRLAN_CLASSNAME,TINYTP_ATTRNAME,iDiscoveredDevice); +} + +/** +Need to connect to the IrLAN port number held in iIrlanPortNumber. Requires +opening up a control socket. +@return TRUE if Success otherwise any error code. +*/ +TInt CIrlanControlEngine::ConnectToProviderL() +{ + TInt ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CONNECT TO PROVIDER\r\n"))); +#endif + iControlSock=new (ELeave) CInternalSocket(); + if ((ret=iControlSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CInternalSocket::OpenL failed with err=%d\r\n"),ret)); +#endif + User::Leave(ret); + } + return DoControlConnect(); +} + +/** +Need to connect to the IrLAN port number held in iIrlanPortNumber. Requires +opening up a control socket. +@return TRUE if Success otherwise any error code. +*/ +TInt CIrlanControlEngine::ConnectToDataChannelL() +{ + TInt ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CONNECT TO DATA CHANNEL\r\n"))); +#endif + iDataSock=new (ELeave) CInternalSocket(); + if ((ret=iDataSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN CInternalSocket::OpenL failed with err=%d\r\n"),ret)); +#endif + User::Leave(ret); + } + return DoDataConnect(); +} + +//*************************** UTILITY FUNCTIONS ********************************** + +/** +Searchs a parameter in the parameter List. +@return A pointer to CIrlanParameter class +*/ +CIrlanParameter* CIrlanControlEngine::LookUpParameter(const TDesC8& aName) +{ + CIrlanParameter *par; + TDblQueIter i(iIrlanParameterList); + + while (par=i++,par!=NULL) + { + if (par->Match(aName)) + return par; + } + return NULL; +} + +void CIrlanControlEngine::SendIrlanResponseFrame(RMBufChain& aPdu) +{ + TInt ret; + ret =iAcceptControlSock->Write(aPdu,NULL,iStatus,0); + if (ret!=KErrNone) + {// what do we do here - panic? +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Failure on iControlSock Send\r\n"))); +#endif + return; + } + SetActive(); + aPdu.Free(); +} + +void CIrlanControlEngine::SendIrlanControlFrame(RMBufChain& aPdu) +{ + TInt ret; + ret =iControlSock->Write(aPdu,NULL,iStatus,0); + if (ret!=KErrNone) + {// what do we do here - panic? +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Failure on iControlSock Send\r\n"))); +#endif + return; + } + SetActive(); + aPdu.Free(); +} + +void CIrlanControlEngine::QueueWaitForControlCommand() +{ + // gotta do something with new data here.... + + iRecvBufPtr.SetLength(iRecvBufLength); + TRAPD(ret,iAcceptControlSock->Recv(iRecvBufPtr,NULL,iStatus,0)); + if (ret !=KErrNone) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Failure on iControlSock Recv - Control Command : %d\r\n"),ret)); +#endif + } + iAwaitingCommand=ETrue; + SetActive(); +} + +void CIrlanControlEngine::QueueWaitForControlResponse() +{ + iRecvBufPtr.SetLength(iRecvBufLength); + TInt ret; + ret =iControlSock->Recv(iRecvBufPtr,NULL,iStatus,0); + if (ret !=KErrNone) + { +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Failure on iControlSock Recv\r\n"))); +#endif + return; + } + iAwaitingResponse=ETrue; + SetActive(); +} + +/** +Asynchronous IAS query. RTimer timeout of 5 seconds on the query. +@param aClassName The Class Name. +@param aAttributeName Attribute name. +@param aRemDevAddr Remote device address. +@return Error code. +*/ +TInt CIrlanControlEngine::DoIASQuery(const TDesC8& aClassName, + const TDesC8& aAttributeName,TUint aRemDevAddr) +{ + TInt ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN IAS Query on \"%S\"|\"%S\"\r\n"),&aClassName,&aAttributeName)); +#endif + // Remember that netDB's return results in SAME buffer. + iQuery.Set(aClassName,aAttributeName,aRemDevAddr); + ret=iNetDatabase->Query(iQuery); + return ret; +} + +TInt CIrlanControlEngine::DoControlConnect() +{ + TSockAddr addr; + // Set home port number. + TUint8 home=KIrlanHomeControlPort; + addr.SetPort(home); + TInt ret=iControlSock->SetLocalName(addr); + if (ret!=KErrNone) + return ret; + addr.SetPort(TUint8(iIrlanControlPortNum)); + // Enable segmentation/reassembly. + TPckgBuf param(1024); // Set segmentation/reassembly size + // const TUint KTinyTPLocalSegmentSize=7: This value is advertised to the + // remote machine as the max amount of data we can reassemble + // const TUint KTinyTPRemoteSegmentSize=8: Remote machine is unable + // to reassemble more data than this. + if ((ret=iControlSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone) + return ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect on SLSAP=%d,DLSAP=%d\r\n"), + home,iIrlanControlPortNum)); +#endif + return iControlSock->Connect(addr); +} + +TInt CIrlanControlEngine::DoDataConnect() +{ + TSockAddr addr; + // Set home port number. + TUint8 home=KIrlanHomeDataPort; + addr.SetPort(home); + TInt ret=iDataSock->SetLocalName(addr); + if (ret!=KErrNone) + return ret; + addr.SetPort(TUint8(iIrlanDataPortNum)); + // Enable segmentation/reassembly. + TPckgBuf param(1518); // Set segmentation/reassembly size + if ((ret=iDataSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone) + return ret; +#ifdef __TRACEWIN__ + LOG(Log::Printf(_L("IRLAN Control channel connect on SLSAP=%d,DLSAP=%d\r\n"), + home,iIrlanDataPortNum)); +#endif + return iDataSock->Connect(addr); +} + +//###################################################################################### + +/** +Constructor. +@param aCIrlan A pointer to CIrlanControlEngine object. +*/ +CIrlanControlEngineTimers::CIrlanControlEngineTimers(CIrlanControlEngine *aCIrlan) +{ + __DECLARE_NAME(_S("CIrlanControlEngineTimers")); + iIrlanControlEngine=aCIrlan; + iIrlanControlEngineTimerH=NULL; +} + +/** +Destructor. +*/ +CIrlanControlEngineTimers::~CIrlanControlEngineTimers() +{ + if (iIrlanControlEngineTimerH) + StopIrlanControlEngineTimer(); +} + +/** +Initialise the value of iIrlanControl for static member functions +@param aCIrlan A pointer to CIrlanControlEngine object. +@return A pointer to CIrlanControlEngineTimers class. +*/ +CIrlanControlEngineTimers *CIrlanControlEngineTimers::NewL(CIrlanControlEngine *aCIrlan) +{ + return new (ELeave) CIrlanControlEngineTimers(aCIrlan); +} + +/** +Invoked to start the Internal Socket timer Can either complete as a call back to the +static CIrlanControlEngine::IrlanControlEngineTimerExpired or can cancel. +@param aCallBack Encapsulates a general call-back function. +@param aTimeout Time out period +*/ +void CIrlanControlEngineTimers::StartIrlanControlEngineTimer(TCallBack aCallBack,TInt aTimeout) +{ + if (iIrlanControlEngineTimerH) + StopIrlanControlEngineTimer(); + iIrlanControlEngineTimer.Set(aCallBack); + iIrlanControlEngineTimerH=&iIrlanControlEngineTimer; + IrlanTimer::Queue(aTimeout,iIrlanControlEngineTimer); +} + +/** +Invoked to stop a previously queued Internal Socket timer +*/ +void CIrlanControlEngineTimers::StopIrlanControlEngineTimer() +{ + if (iIrlanControlEngineTimerH) + IrlanTimer::Remove(iIrlanControlEngineTimer); + iIrlanControlEngineTimerH=NULL; +} + +void CIrlanControlEngineTimers::DoIrlanControlEngineTimerExpired() +{ + iIrlanControlEngineTimerH=NULL; +}