linklayerprotocols/ethernetnif/IRLAN/IRLANCTL.CPP
changeset 0 af10295192d8
child 5 1422c6cd3f0c
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Irlan connection control engine 
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 #include <nifman.h>
       
    23 #include <nifvar.h>
       
    24 #include <nifutl.h>
       
    25 #include <es_mbuf.h>
       
    26 #include <in_pkt.h>
       
    27 #include <ir_sock.h>
       
    28 #include "PKTDRV.H"
       
    29 #include "ETHINTER.H"
       
    30 #include "IRLAN.H"
       
    31 #include "IRLANUTL.H"
       
    32 #include "INTSOCK.H"
       
    33 #include "IRLANBUF.H"
       
    34 #include "IRLANDAT.H"
       
    35 #include "irlantimer.h"
       
    36 
       
    37 //#define __TRACEWIN__
       
    38 #ifdef __TRACEWIN__
       
    39   #include <log.h>
       
    40 #else
       
    41   #define LOG(a)
       
    42 #endif
       
    43 
       
    44 /**
       
    45 Create a new CIrlanControlEngine object.
       
    46 @param aPktDrv A pointer to CIrlanPktDrv object.
       
    47 @return A pointer to CIrlanControlEngine object.
       
    48 */
       
    49 CIrlanControlEngine *CIrlanControlEngine::NewL(CIrlanPktDrv* aPktDrv)
       
    50 {
       
    51 #ifdef __TRACEWIN__
       
    52 	LOG(Log::Printf(_L("IRLAN	CIrlanControlEngine::NewL\r\n")));
       
    53 #endif
       
    54 	CIrlanControlEngine *cc=new (ELeave) CIrlanControlEngine;
       
    55 	CleanupStack::PushL(cc);
       
    56 	cc->ConstructL(aPktDrv);
       
    57 	CActiveScheduler::Add(cc);
       
    58 	CleanupStack::Pop();
       
    59 	return cc;
       
    60 }
       
    61 
       
    62 /**
       
    63 Think this should be a deferred deletion here especially
       
    64 if IrLAN is already connected.
       
    65 Destructor.
       
    66 */
       
    67 CIrlanControlEngine::~CIrlanControlEngine()
       
    68 {
       
    69 	LOG(Log::Printf(_L("IRLAN	~CIrlanControlEngine\r\n")));
       
    70 	CIrlanParameter *par;
       
    71 	TDblQueIter<CIrlanParameter> i(iIrlanParameterList);
       
    72 	while (par=i++,par!=NULL)
       
    73 		{
       
    74 		par->iLink.Deque();
       
    75 		delete par;
       
    76 		}
       
    77 	iDataSendQ.Free();
       
    78 
       
    79 	if (iTimers)
       
    80 		iTimers->StopIrlanControlEngineTimer();
       
    81 	delete iTimers;
       
    82 	if (iSender)
       
    83 		{
       
    84 		iSender->Cancel();
       
    85 		delete iSender;
       
    86 		}
       
    87 	if (iReceiver)
       
    88 		{
       
    89 		iReceiver->Cancel();
       
    90 		delete iReceiver;
       
    91 		}
       
    92 	delete iHostResolver;   // do close on this too?
       
    93 	delete iNetDatabase;	// do close on this too?
       
    94 	if (iDataSock)
       
    95 		iDataSock->Close();
       
    96 	if (iControlSock)
       
    97 		iControlSock->Close();
       
    98 
       
    99 	delete iRecvBuffer;
       
   100 	CActive::Cancel();
       
   101 }
       
   102 
       
   103 /**
       
   104 Default constructor
       
   105 */
       
   106 CIrlanControlEngine::CIrlanControlEngine()
       
   107 	:CActive(EIrlanControlPriority)
       
   108 	,iRecvBufPtr(NULL,0)
       
   109 {
       
   110 }
       
   111 
       
   112 /**
       
   113 The CIrlanControlEngine::ConstructL performs all the memory allocating initialisations.
       
   114 @param aNotify A pointer to CIrlanPktDrv object.
       
   115 */
       
   116 void CIrlanControlEngine::ConstructL(CIrlanPktDrv* aNotify)
       
   117 {
       
   118 #ifdef __TRACEWIN__
       
   119 	LOG(Log::Printf(_L("IRLAN	CIrlanControlEngine::ConstructL\r\n")));
       
   120 #endif
       
   121 	iRecvBufLength=KIrlanBufSize;
       
   122 	iTimers=CIrlanControlEngineTimers::NewL(this);
       
   123 	iRecvBuffer=HBufC8::NewMaxL(iRecvBufLength);
       
   124 	TPtr8 temp=iRecvBuffer->Des();
       
   125 	iRecvBufPtr.Set(temp);
       
   126 	iNotify=aNotify;
       
   127     iIrlanParameterList.SetOffset(_FOFF(CIrlanParameter,iLink));
       
   128 }
       
   129 
       
   130 /**
       
   131 Handles Errors.
       
   132 */
       
   133 void CIrlanControlEngine::HandleErrorL()
       
   134 {
       
   135 #ifdef __TRACEWIN__
       
   136 	LOG(Log::Printf(_L("IRLAN	Error in CIrlanControlEngine::RunL\r\n")));
       
   137 #endif
       
   138    	switch (iState)
       
   139 		{
       
   140 	case E_Idle:
       
   141 	case E_Query:
       
   142 	case E_Conn:
       
   143 		PassiveIdleTransitionL();
       
   144 		iState=E_PassiveIdle;
       
   145 		iDiscoveredDevice=0;
       
   146 		break;
       
   147 	case E_Data:
       
   148 		{
       
   149 		iState=E_Idle;
       
   150 		iDiscoveredDevice=0;
       
   151 		TPtr8 dest(&iHWAddr[0],6,6);
       
   152 		dest.FillZ(6);
       
   153 		// Tear down the link stuff.
       
   154 		delete iSender;
       
   155 		iSender=0;
       
   156 		delete iReceiver;
       
   157 		iReceiver=0;
       
   158 		break;
       
   159 		}
       
   160 	default:
       
   161 		break;
       
   162 		}
       
   163 }
       
   164 
       
   165 /**
       
   166 Irlan state machine - on hitting this RunL, either iStatus is KErrNone in which case
       
   167 we have completed OK and can try the next stage or it isn't in which case we must
       
   168 handle the error appropriately.  The state machine is only rearmed if the phase action
       
   169 produces some error.  Otherwise, it is left up to the IrDA PRT to call back via the
       
   170 socket/hostresolver/netDB notifer and for the request to be completed that way.
       
   171 */
       
   172 void CIrlanControlEngine::RunL()
       
   173 {
       
   174 #ifdef __TRACEWIN__
       
   175 	PrintState();
       
   176 #endif
       
   177 	RMBufChain pkt;
       
   178 	TInt ret=KErrNone;
       
   179 	if (iStatus!=KErrNone)
       
   180 		{
       
   181 		HandleErrorL();
       
   182 		return;
       
   183 		}
       
   184 	switch (iState)
       
   185 		{
       
   186 	case E_Idle:
       
   187 		if (iDiscoveredDevice)
       
   188 			{// An IrDA discovery has been successfully completed.
       
   189 //			iHostResolver.Close();
       
   190 			TRAP(ret,QueryRemoteIASL());
       
   191 			User::LeaveIfError(ret);
       
   192 			iState=E_Query;
       
   193 			break;
       
   194 			}
       
   195 		ret=AttemptingDiscoveryL();
       
   196 		// a KErrNone here indicates we're doing a discovery...
       
   197 		// any other error will be picked up as a PassiveIdleTransition
       
   198 		break;
       
   199 	case E_PassiveIdle:
       
   200 		// the remote side has successfully connected to us
       
   201 		// now we wait on receipt of remote command frames
       
   202 		QueueWaitForControlCommand();
       
   203 		iState=E_Info;
       
   204 		break;
       
   205 	case E_Query:
       
   206 		// A query on remote device's IAS has successfully completed.
       
   207   		iOpenRetries=0;
       
   208   		ret=ConnectToProviderL();
       
   209   		iState=E_Conn;
       
   210   		break;
       
   211 	case E_Conn:
       
   212 		// Completed OK - send the GetInfoCmd
       
   213 		ret=GetInfoCmd();
       
   214 		iState=E_Info;
       
   215 		break;
       
   216 	case E_Info:
       
   217 		// Need to parse response from this query if it comes.
       
   218 		switch (iAccessType)
       
   219 			{
       
   220 		case EAccessPoint:
       
   221 			if (iAwaitingResponse)
       
   222 				{
       
   223 				ParseInfoReply();
       
   224 				ret=GetMediaCmd();
       
   225 				iState=E_Media;
       
   226 				break;
       
   227 				}
       
   228 			QueueWaitForControlResponse();
       
   229 			break;
       
   230 		case EPeerToPeer:
       
   231 			if (iAwaitingCommand)
       
   232 				{
       
   233 				ParseControlCommand();  // also sends the reply
       
   234 				break;
       
   235 				}
       
   236 			QueueWaitForControlCommand();
       
   237 			break;
       
   238 		case EHosted:
       
   239 			break;
       
   240 			}
       
   241 		break;
       
   242 	case E_Media:
       
   243 		if (iAwaitingResponse)
       
   244 			{
       
   245 			ret=ParseMediaReply();
       
   246 			User::LeaveIfError(ret);
       
   247 			ret=OpenDataCmd();
       
   248 			iState=E_Open;
       
   249 			break;
       
   250 			}
       
   251 		QueueWaitForControlResponse();
       
   252 		break;
       
   253 	case E_Open:
       
   254 		if (iAwaitingResponse)
       
   255 			{
       
   256 			ParseOpenDataReply();
       
   257 			// WE'RE ONLY SUPPORTING ACCESS MODE IRLAN AT PRESENT
       
   258 			__ASSERT_DEBUG(iAccessType==EAccessPoint,IrlanUtil::Fault(EIrlanInvalidIrlanMode));
       
   259 			ret=GetDirectedFilterConfigCmd();
       
   260 			iState=E_FilterConfig;
       
   261 			break;
       
   262 			}
       
   263 		QueueWaitForControlResponse();
       
   264 		break;
       
   265 	case E_FilterConfig:
       
   266 		// This is an extra state I've added to handle filter config stuff
       
   267 		if (iAwaitingResponse)
       
   268 			{
       
   269 			ParseDirectedFilterConfigReply();
       
   270 			ret=SetDirectedFilterOperationCmd();
       
   271 			iState=E_FilterOperation;
       
   272 			break;
       
   273 			}
       
   274 		QueueWaitForControlResponse();
       
   275 		break;
       
   276 	case E_FilterOperation:
       
   277 		// This is an extra state I've added to handle filter operation stuff
       
   278 		if (iAwaitingResponse)
       
   279 			{
       
   280 			ParseDirectedFilterOperationReply();
       
   281 			ret=SetBroadcastFilterOperationCmd();
       
   282 			iState=E_FilterBroadcast;
       
   283 			break;
       
   284 			}
       
   285 		QueueWaitForControlResponse();
       
   286 		break;
       
   287 	case E_FilterBroadcast:
       
   288 		// This is an extra state I've added to handle broadcast filter stuff
       
   289 		if (iAwaitingResponse)
       
   290 			{
       
   291 			ParseBroadcastFilterOperationReply();
       
   292 			ConnectToDataChannelL();
       
   293 			break;
       
   294 			}
       
   295 		QueueWaitForControlResponse();
       
   296 		break;
       
   297 	case E_Wait:
       
   298 		// Only needed if acting as a provd.
       
   299 		break;
       
   300 	case E_Arb:
       
   301 		// Only needed if acting as a provd.
       
   302 		break;
       
   303 	case E_Data:
       
   304 		// Once we're here, we can send/receive ethernet packets as data over IrLAN.
       
   305 		iSender=CIrlanSender::NewL(this,iDataSock);
       
   306 		iReceiver=CIrlanReceiver::NewL(this,iDataSock);
       
   307  		iReceiver->QueueRead();
       
   308 		if (iDataSendQ.Remove(pkt))
       
   309 			{
       
   310 			iSender->QueueSend(pkt);
       
   311 			pkt.Free();
       
   312 			}
       
   313         iNotify->LinkLayerUp(); //bring up the tcpip stack ect.
       
   314 		return;
       
   315 	case E_Close:
       
   316 
       
   317 		break;
       
   318 	case E_Sync:
       
   319 		break;
       
   320 	default:
       
   321 		IrlanUtil::Panic(EIrlanErrorState);
       
   322 		break;
       
   323 		}
       
   324 	if (ret!=KErrNone)
       
   325 	  	ActivateStateMachine(ret);
       
   326 }
       
   327 
       
   328 
       
   329 /**
       
   330 Process the packet received from the LinkLayer.
       
   331 */
       
   332 void CIrlanControlEngine::ProcessReceivedPacketL()
       
   333 {
       
   334 	RMBufPacket pkt;
       
   335 
       
   336 	pkt.CreateL(iRecvBufPtr,0);
       
   337 	pkt.Pack();
       
   338 	iNotify->Process(pkt);	// We had a read queued and that has completed
       
   339 }
       
   340 
       
   341 
       
   342 /**
       
   343 Starts up the state machine in E_Idle state - will lead to a discovery attempt.
       
   344 */
       
   345 void CIrlanControlEngine::StartL()
       
   346 {
       
   347 	TInt ret;
       
   348 	iHostResolver=CInternalHostResolver::NewL();
       
   349 	if ((ret=iHostResolver->OpenL(_L("IrTinyTP"),this))!=KErrNone)
       
   350 		{
       
   351 		LOG(Log::Printf(_L("IRLAN	CInternalHostResolver::OpenL failed with err=%d\r\n"),ret));
       
   352 		User::Leave(ret);
       
   353 		}
       
   354 	iState=E_Idle;
       
   355 	iProtocol=iHostResolver->iProtocol;
       
   356 	ActivateStateMachine();
       
   357 }
       
   358 
       
   359 /**
       
   360 cancellation of an outstanding request.
       
   361 */
       
   362 void CIrlanControlEngine::DoCancel()
       
   363 {
       
   364 	switch (iState)
       
   365 		{
       
   366 	case E_Data:
       
   367 		iSender->DoCancel();
       
   368 		iReceiver->DoCancel();
       
   369 		break;
       
   370 	default:
       
   371 		break;
       
   372 		}
       
   373 }
       
   374 
       
   375 /** 
       
   376 Protocol inspects return
       
   377 It blocks sending if it receives a return <= 0
       
   378 This value should be propogated up through the stack
       
   379 @internalComponent
       
   380 */
       
   381 const TInt KStopSending		= 0;
       
   382 
       
   383 /**
       
   384 Protocol inspects return to indicate Keep sending the data.
       
   385 @internalComponent
       
   386 */
       
   387 const TInt KContinueSending	= 1;
       
   388 
       
   389 /**
       
   390 Sender Class is generic and does not want to know about RMBuf's
       
   391 Copy to a Heap Buffer and Free the packet. EtherII MAC layer comments
       
   392 Say we should free the packet buffer
       
   393 RMBuf could contain a chain so get into a contiguous buffer
       
   394 @param aPdu		A reference to the packet to be sent (really an RMBufPkt)
       
   395 @param aSource  A pointer to the source protocol.
       
   396 @return 0 Tells the higher layer to stop sending the data.
       
   397 		1 Tells higher layer that it can continue sending more data.
       
   398 */
       
   399 TInt CIrlanControlEngine::Send(RMBufChain& aPdu, TAny*)
       
   400 {
       
   401 	if (iState!=E_Data)
       
   402 		{// Not ready to send the packet.
       
   403 		aPdu.Free();
       
   404 		return KStopSending;
       
   405 		}
       
   406 	// Need to stick the packet in a queue and kick the sender...
       
   407 	iDataSendQ.Append(aPdu);
       
   408 	iSender->KickSender();
       
   409 	return KContinueSending;
       
   410 }
       
   411 
       
   412 
       
   413 /**
       
   414 This kicks off the state machine active object.  Completion in RunL..
       
   415 @param aStat The active object Request complete status.
       
   416 */
       
   417 void CIrlanControlEngine::ActivateStateMachine(TInt aStat)
       
   418 {
       
   419 	TRequestStatus *pS=&iStatus;
       
   420 	User::RequestComplete(pS,aStat);
       
   421 	SetActive();
       
   422 }
       
   423 
       
   424 //*************************** NOTIFIERS **********************************
       
   425 
       
   426 /**
       
   427 Upcall from SAP - more data arrived
       
   428 Indicates that new data is available on a service access point
       
   429 */
       
   430 void CIrlanControlEngine::NewData(TUint /*aCount*/)
       
   431 {
       
   432 }
       
   433 
       
   434 /**
       
   435 Upcall from SAP - flow control on
       
   436 Indicates that new buffer space is available on a service 
       
   437 */
       
   438 void CIrlanControlEngine::CanSend()
       
   439 {
       
   440 	if (iState==E_Data)
       
   441 		{
       
   442 #ifdef __TRACEWIN__
       
   443 	LOG(Log::Printf(_L("IRLAN	CanSend received from SAP\r\n")));
       
   444 #endif
       
   445 		// if there's any data in the queue, force send it!
       
   446 		if (!iDataSendQ.IsEmpty())
       
   447 			iSender->KickSender();
       
   448 		return;
       
   449 		}
       
   450 }
       
   451 
       
   452 /**
       
   453 This returns the hardware address pulled out of response to
       
   454 IrLAN FILTER_OPERATION/DYNAMIC request.
       
   455 @return NULL Failure.
       
   456 		(NULL Terminated Binary String) The Hardware Address of the interface. LAN Device 
       
   457 		Specific
       
   458 @note this will not contain the correct MAC address until IRLAN recives a control frame.
       
   459 */
       
   460 TUint8* CIrlanControlEngine::GetInterfaceAddress()
       
   461 {
       
   462 	return &iHWAddr[0];
       
   463 }
       
   464 
       
   465 /**
       
   466 Upcall from SAP.  Notify layer above
       
   467 Indicates that a connection attempt has completed successfully
       
   468 */
       
   469 void CIrlanControlEngine::ConnectComplete()
       
   470 {
       
   471 #ifdef __TRACEWIN__
       
   472 	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 1\r\n")));
       
   473 #endif
       
   474 	ActivateStateMachine();
       
   475 }
       
   476 
       
   477 #pragma warning (disable:4100)
       
   478 /**
       
   479 Upcall from SAP.  Notify layer above
       
   480 Indicates that a connection attempt has completed successfully
       
   481 @param aConnectData Connect data (if supported)  
       
   482 */
       
   483 void CIrlanControlEngine::ConnectComplete(const TDesC8& /*aConnectData*/)
       
   484 {
       
   485 	PrintState();
       
   486 	TInt ret=KErrNone;
       
   487 	switch (iState)
       
   488 		{
       
   489 	case E_Conn:
       
   490 		// Successful completion of control channel connect.
       
   491 #ifdef __TRACEWIN__
       
   492 	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length()));
       
   493 #endif
       
   494 		break;
       
   495 	case E_FilterBroadcast:
       
   496 		// Successful completion of data channel connect.
       
   497 #ifdef __TRACEWIN__
       
   498 	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length()));
       
   499 #endif
       
   500 	    iState=E_Data;			// READY TO TRY AND SEND/RECEIVE PACKETS!
       
   501 		break;
       
   502 	default:
       
   503 		ret=KErrNotSupported;
       
   504 		break;
       
   505 		}
       
   506 	ActivateStateMachine(ret);
       
   507 }
       
   508 #pragma warning (default:4100)
       
   509 
       
   510 /**
       
   511 Upcall from SAP.  Notify layer above
       
   512 Indicates that a connection attempt has completed successfully
       
   513 @param aSSP The new SSP for passive opens 
       
   514 */
       
   515 void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP)
       
   516 {
       
   517 #ifdef __TRACEWIN__
       
   518 	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 3 - not supported!!\r\n")));
       
   519 #endif
       
   520 	iAcceptControlSock=CInternalSocket::NewL(&aSSP,this);
       
   521 	ActivateStateMachine();
       
   522 }
       
   523 
       
   524 /**
       
   525 Upcall from SAP.  Notify layer above
       
   526 Indicates that a connection attempt has completed successfully
       
   527 @param aSSP The new SSP for passive opens 
       
   528 @param aConnectData Connect data (if supported)  
       
   529 */
       
   530 void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP,
       
   531   const TDesC8& /*aConnectData*/)
       
   532 {
       
   533 #ifdef __TRACEWIN__
       
   534 	LOG(Log::Printf(_L("IRLAN	Control channel connect complete on accept socket\r\n")));
       
   535 #endif
       
   536 	iAcceptControlSock=CInternalSocket::NewL(&aSSP,this);
       
   537 	ActivateStateMachine();
       
   538 }
       
   539 
       
   540 /**
       
   541 Upcall from SAP.  Notify layer above.
       
   542 Indicates that the SAP has finished closing down
       
   543 @param aDelete     Delete SAP 
       
   544 */
       
   545 void CIrlanControlEngine::CanClose(TDelete /*aDelete*/)
       
   546 {
       
   547 }
       
   548 
       
   549 /**
       
   550 Upcall from SAP.  Notify layer above.
       
   551 Indicates that the SAP has finished closing down
       
   552 @param aDisconnectData Any user data carried on the disconnect frame 
       
   553 @param aDelete         Delete SAP 
       
   554 */
       
   555 void CIrlanControlEngine::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/)
       
   556 {
       
   557 }
       
   558 
       
   559 /**
       
   560 Upcall from SAP - Error notification.
       
   561 @param aError			The error code
       
   562 @param anOperationMask  A bitmask of TOperationBitmasks values specifying which pending operations are
       
   563 						affected by the Error up-call
       
   564 */
       
   565 void CIrlanControlEngine::Error(TInt /*anError*/,TUint /*anOperationMask*/)
       
   566 {
       
   567 }
       
   568 
       
   569 /**
       
   570 Upcall from SAP - Not supported
       
   571 Indicates that the other end of a connection has disconnected. 
       
   572 */
       
   573 void CIrlanControlEngine::Disconnect(void)
       
   574 {
       
   575 }
       
   576 
       
   577 /**
       
   578 Indicates that the other end of a connection has disconnected
       
   579 
       
   580 @param aDisconnectData User data in the disconnect frame.
       
   581 */
       
   582 void CIrlanControlEngine::Disconnect(TDesC8& /*aDisconnectData*/)
       
   583 {
       
   584 }
       
   585 
       
   586 /**
       
   587 Upcall from SAP.  Notify layer above
       
   588 Indicates that the currently pending Ioctl has completed
       
   589 @param aBuf Any data requested by the Ioctl operation.
       
   590 */
       
   591 void CIrlanControlEngine::IoctlComplete(TDesC8 * /*aBuf*/)
       
   592 {
       
   593 }
       
   594 
       
   595 void CIrlanControlEngine::NoBearer(const TDesC8& /*aConnectionParams*/)
       
   596 {
       
   597 }
       
   598 
       
   599 void CIrlanControlEngine::Bearer(const TDesC8& /*aConnectionInfo*/)
       
   600 {
       
   601 }
       
   602 
       
   603 /**
       
   604 Depending on error AND STATE!!, need to take corresponding action.
       
   605 Notifier call back from IrDA PRT
       
   606 This is where the request completes - it has already filled
       
   607 in the name record passed through to GetByName so leave that.
       
   608 @param aErr Error code.
       
   609 */
       
   610 void CIrlanControlEngine::QueryComplete(TInt aError)
       
   611 {
       
   612 	PrintState();
       
   613 	switch (iState)
       
   614 		{
       
   615 	case E_Idle:
       
   616 		if (aError==KErrNone)	// Successful discovery
       
   617 			{// iLog already filled in - pull out the device.
       
   618 			TIrdaSockAddr addr(iLog().iAddr);
       
   619 			// Check it has IrLAN set in it's discovery hint bits.
       
   620 			iDiscoveredDevice=addr.GetRemoteDevAddr();
       
   621 #ifdef __TRACEWIN__
       
   622 			TUint numHintBytes=addr.GetServiceHintByteCount();
       
   623 			TUint8 hintByte1=addr.GetFirstServiceHintByte();
       
   624 			LOG(Log::Printf(_L("IRLAN	!!!!!!!!!!!!! SUCCESSFUL DISCOVERY !!!!!!!!!!!!!!!\r\n")));
       
   625 			LOG(Log::Printf(_L("IRLAN	Remote machine dev addr=0x%08x\r\n"),iDiscoveredDevice));
       
   626 			LOG(Log::Printf(_L("IRLAN	Remote no. of service hint bytes is %d\r\n"),numHintBytes));
       
   627 			LOG(Log::Printf(_L("IRLAN	Remote first service hint byte is 0x%02x\r\n"),hintByte1));
       
   628 			if (numHintBytes>1)
       
   629 				{
       
   630 				LOG(Log::Printf(_L("IRLAN	Remote second service hint byte is 0x%02x\r\n"),
       
   631 					addr.GetSecondServiceHintByte()));
       
   632 				}
       
   633 			LOG(Log::Printf(_L("IRLAN	Remote machine name is \"%s\"\r\n"),iLog().iName.PtrZ()));
       
   634 #endif
       
   635 			}
       
   636 		else					// Nothing discovered
       
   637 			aError=KErrNone;	// This will ensure continued attempts.
       
   638 		break;
       
   639 	case E_Query:
       
   640 		if (aError==KErrNone)
       
   641 			{// IAS QUERY COMPLETED SUCCESSFULLY.
       
   642 			iResults.Copy(iQuery);
       
   643 			PrintIASResults();
       
   644 			if (iResults.Type()==EIASDataInteger)
       
   645 				{
       
   646 				aError=iResults.GetInteger(iIrlanControlPortNum);
       
   647 				}
       
   648 			}
       
   649 		else
       
   650 			{// IAS QUERY COMPLETED UNSUCCESSFULLY.
       
   651 			PrintIASError(aError);
       
   652 			// Need to take corrective action!! (Done in HandleErrorL).
       
   653 			}
       
   654 		break;
       
   655 	default:
       
   656 		break;
       
   657 		}
       
   658 	ActivateStateMachine(aError);	// Kick off state machine again.
       
   659 }
       
   660 
       
   661 //********************** IRLAN STATE MACHINE ACTIONS ************************
       
   662 
       
   663 TInt CIrlanControlEngine::PassiveIdleTransitionL()
       
   664 {
       
   665 #ifdef __TRACEWIN__
       
   666 	LOG(Log::Printf(_L("IRLAN	PASSIVE IDLE STATE TRANSITION\r\n")));
       
   667 #endif
       
   668 	// first - queue the IAS db entry.
       
   669 	TIASDatabaseEntry iasentry;
       
   670 	if (!iNetDatabase)
       
   671 		{
       
   672 		iNetDatabase=CInternalNetDB::NewL();
       
   673 		User::LeaveIfError(iNetDatabase->OpenL(TINYTP_PROTOCOL,this));
       
   674 		}
       
   675 	iasentry.SetClassName(IRLAN_CLASSNAME);
       
   676 	iasentry.SetAttributeName(TINYTP_ATTRNAME);
       
   677 	iasentry.SetToInteger(9);
       
   678 	iNetDatabase->Add(iasentry);
       
   679 #ifdef __TRACEWIN__
       
   680 	LOG(Log::Printf(_L("IrLAN	PEER service registered on port 9\r\n")));
       
   681 #endif
       
   682 
       
   683 	iListenSock=new (ELeave) CInternalSocket();
       
   684 	User::LeaveIfError(iListenSock->OpenL(TINYTP_PROTOCOL,this));
       
   685 	TIrdaSockAddr addr(iLog().iAddr);
       
   686 	addr.SetPort(0x09);					    // This is where IrLAN PEER is.
       
   687 	iListenSock->SetLocalName(addr);
       
   688 	iListenSock->WaitForConnect(2);
       
   689 
       
   690 	iAccessType=EPeerToPeer;
       
   691 	/*
       
   692 	ret=iAcceptor->Open();
       
   693 	sock1.Accept(sock2,iStatus);	// the order of this accept call has changed in esock
       
   694 	User::WaitForRequest(stat3);
       
   695 	// second - do a listen and accept on corresponding port.
       
   696 	*/
       
   697 
       
   698 	return KErrNone;
       
   699 }
       
   700 
       
   701 TInt CIrlanControlEngine::AttemptingDiscoveryL()
       
   702 {
       
   703 #ifdef __TRACEWIN__
       
   704 	LOG(Log::Printf(_L("IRLAN	ATTEMPTING DISCOVERY\r\n")));
       
   705 #endif
       
   706 	if (!iDiscoveryAttempts)
       
   707 		{
       
   708 		iLog().iName=_S("*");
       
   709 		iDiscoveryAttempts++;
       
   710 	    TInt ret=iHostResolver->GetByName(iLog());
       
   711 		return ret;
       
   712 		}
       
   713 	else
       
   714 		{
       
   715 		if (iDiscoveryAttempts>=5)
       
   716 			{// need to drop into passive idle state
       
   717 			return KErrNotFound;
       
   718 			}
       
   719 		// 1 sec between discoveries
       
   720 		TCallBack callback(CIrlanControlEngine::IrlanControlEngineTimerExpired,this);
       
   721 		iTimers->StartIrlanControlEngineTimer(callback,1000000L);
       
   722 		}
       
   723 	return KErrNone;  // don't want to reactivate state machine
       
   724 }
       
   725 
       
   726 TInt CIrlanControlEngine::IrlanControlEngineTimerExpired(TAny *aIrlan)
       
   727 {
       
   728 	CIrlanControlEngine *cc=(CIrlanControlEngine *)aIrlan;
       
   729 	switch (cc->iState)
       
   730 		{
       
   731 	case E_Idle:
       
   732 		// discovery timer has completed.  try a discovery.
       
   733 		cc->iTimers->DoIrlanControlEngineTimerExpired();
       
   734 		cc->iDiscoveryAttempts++;
       
   735 		cc->iHostResolver->GetByName(cc->iLog());
       
   736 		break;
       
   737 	default:
       
   738 		break;
       
   739 		}
       
   740 	return 0;
       
   741 }
       
   742 
       
   743 /**
       
   744 Need to find out if the remote supports IrLAN.  Note that this will involve
       
   745 kicking up the IrLAP/IAS connections.  Requires opening up a net database.
       
   746 @return TRUE if the Classname, AttributeType and the Device is present otherwise some error code.
       
   747 */
       
   748 TInt CIrlanControlEngine::QueryRemoteIASL()
       
   749 {
       
   750 	TInt ret;
       
   751 #ifdef __TRACEWIN__
       
   752 	LOG(Log::Printf(_L("IRLAN	QUERY REMOTE IAS\r\n")));
       
   753 #endif
       
   754 	TRAP(ret,iNetDatabase=CInternalNetDB::NewL());
       
   755 	User::LeaveIfError(ret);
       
   756 	if ((ret=iNetDatabase->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
       
   757 		{
       
   758 #ifdef __TRACEWIN__
       
   759 		LOG(Log::Printf(_L("IRLAN	CInternalNetDB::OpenL failed with err=%d\r\n"),ret));
       
   760 #endif
       
   761 		User::Leave(ret);
       
   762 		}
       
   763 	return DoIASQuery(IRLAN_CLASSNAME,TINYTP_ATTRNAME,iDiscoveredDevice);
       
   764 }
       
   765 
       
   766 /**
       
   767 Need to connect to the IrLAN port number held in iIrlanPortNumber.  Requires
       
   768 opening up a control socket.
       
   769 @return TRUE if Success otherwise any error code.
       
   770 */
       
   771 TInt CIrlanControlEngine::ConnectToProviderL()
       
   772 {
       
   773 	TInt ret;
       
   774 #ifdef __TRACEWIN__
       
   775 	LOG(Log::Printf(_L("IRLAN	CONNECT TO PROVIDER\r\n")));
       
   776 #endif
       
   777 	iControlSock=new (ELeave) CInternalSocket();
       
   778 	if ((ret=iControlSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
       
   779 		{
       
   780 #ifdef __TRACEWIN__
       
   781 		LOG(Log::Printf(_L("IRLAN	CInternalSocket::OpenL failed with err=%d\r\n"),ret));
       
   782 #endif
       
   783 		User::Leave(ret);
       
   784 		}
       
   785 	return DoControlConnect();
       
   786 }
       
   787 
       
   788 /**
       
   789 Need to connect to the IrLAN port number held in iIrlanPortNumber.  Requires
       
   790 opening up a control socket.
       
   791 @return TRUE if Success otherwise any error code.
       
   792 */
       
   793 TInt CIrlanControlEngine::ConnectToDataChannelL()
       
   794 {
       
   795 	TInt ret;
       
   796 #ifdef __TRACEWIN__
       
   797 	LOG(Log::Printf(_L("IRLAN	CONNECT TO DATA CHANNEL\r\n")));
       
   798 #endif
       
   799 	iDataSock=new (ELeave) CInternalSocket();
       
   800 	if ((ret=iDataSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
       
   801 		{
       
   802 #ifdef __TRACEWIN__
       
   803 		LOG(Log::Printf(_L("IRLAN	CInternalSocket::OpenL failed with err=%d\r\n"),ret));
       
   804 #endif
       
   805 		User::Leave(ret);
       
   806 		}
       
   807 	return DoDataConnect();
       
   808 }
       
   809 
       
   810 //*************************** UTILITY FUNCTIONS **********************************
       
   811 
       
   812 /**
       
   813 Searchs a parameter in the parameter List.
       
   814 @return A pointer to CIrlanParameter class
       
   815 */
       
   816 CIrlanParameter* CIrlanControlEngine::LookUpParameter(const TDesC8& aName)
       
   817 {
       
   818 	CIrlanParameter *par;
       
   819 	TDblQueIter<CIrlanParameter> i(iIrlanParameterList);
       
   820 
       
   821 	while (par=i++,par!=NULL)
       
   822 		{
       
   823 		if (par->Match(aName))
       
   824 			return par;
       
   825 		}
       
   826 	return NULL;
       
   827 }
       
   828 
       
   829 void CIrlanControlEngine::SendIrlanResponseFrame(RMBufChain& aPdu)
       
   830 {
       
   831 	TInt ret;
       
   832 	ret =iAcceptControlSock->Write(aPdu,NULL,iStatus,0);
       
   833 	if (ret!=KErrNone)
       
   834 		{// what do we do here - panic?
       
   835 #ifdef __TRACEWIN__
       
   836 		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Send\r\n")));
       
   837 #endif
       
   838 		return;
       
   839 		}
       
   840 	SetActive();
       
   841 	aPdu.Free();
       
   842 }
       
   843 
       
   844 void CIrlanControlEngine::SendIrlanControlFrame(RMBufChain& aPdu)
       
   845 {
       
   846 	TInt ret;
       
   847 	ret =iControlSock->Write(aPdu,NULL,iStatus,0);
       
   848 	if (ret!=KErrNone)
       
   849 		{// what do we do here - panic?
       
   850 #ifdef __TRACEWIN__
       
   851 		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Send\r\n")));
       
   852 #endif
       
   853 		return;
       
   854 		}
       
   855 	SetActive();
       
   856 	aPdu.Free();
       
   857 }
       
   858 
       
   859 void CIrlanControlEngine::QueueWaitForControlCommand()
       
   860 {
       
   861 	// gotta do something with new data here....
       
   862 
       
   863 	iRecvBufPtr.SetLength(iRecvBufLength);
       
   864 	TRAPD(ret,iAcceptControlSock->Recv(iRecvBufPtr,NULL,iStatus,0));
       
   865 	if (ret !=KErrNone)
       
   866 		{
       
   867 #ifdef __TRACEWIN__		
       
   868 		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Recv - Control Command : %d\r\n"),ret));
       
   869 #endif		
       
   870 		}
       
   871 	iAwaitingCommand=ETrue;
       
   872 	SetActive();
       
   873 }
       
   874 
       
   875 void CIrlanControlEngine::QueueWaitForControlResponse()
       
   876 {
       
   877 	iRecvBufPtr.SetLength(iRecvBufLength);
       
   878 	TInt ret;
       
   879 	ret =iControlSock->Recv(iRecvBufPtr,NULL,iStatus,0);
       
   880 	if (ret !=KErrNone)
       
   881 		{
       
   882 #ifdef __TRACEWIN__
       
   883 		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Recv\r\n")));
       
   884 #endif
       
   885 		return;
       
   886 		}
       
   887 	iAwaitingResponse=ETrue;
       
   888 	SetActive();
       
   889 }
       
   890 
       
   891 /**
       
   892 Asynchronous IAS query.  RTimer timeout of 5 seconds on the query.
       
   893 @param aClassName		The Class Name.
       
   894 @param aAttributeName	Attribute name.
       
   895 @param aRemDevAddr		Remote device address.
       
   896 @return Error code.
       
   897 */
       
   898 TInt CIrlanControlEngine::DoIASQuery(const TDesC8& aClassName,
       
   899   const TDesC8& aAttributeName,TUint aRemDevAddr)
       
   900 {
       
   901 	TInt ret;
       
   902 #ifdef __TRACEWIN__
       
   903 	LOG(Log::Printf(_L("IRLAN	IAS Query on \"%S\"|\"%S\"\r\n"),&aClassName,&aAttributeName));
       
   904 #endif
       
   905 	// Remember that netDB's return results in SAME buffer.
       
   906 	iQuery.Set(aClassName,aAttributeName,aRemDevAddr);
       
   907 	ret=iNetDatabase->Query(iQuery);
       
   908 	return ret;
       
   909 }
       
   910 
       
   911 TInt CIrlanControlEngine::DoControlConnect()
       
   912 {
       
   913 	TSockAddr addr;
       
   914 	// Set home port number.
       
   915 	TUint8 home=KIrlanHomeControlPort;
       
   916 	addr.SetPort(home);
       
   917 	TInt ret=iControlSock->SetLocalName(addr);
       
   918 	if (ret!=KErrNone)
       
   919 		return ret;
       
   920 	addr.SetPort(TUint8(iIrlanControlPortNum));
       
   921 	// Enable segmentation/reassembly.
       
   922 	TPckgBuf<TUint> param(1024);	// Set segmentation/reassembly size
       
   923 	// const TUint KTinyTPLocalSegmentSize=7: This value is advertised to the
       
   924 	// remote machine as the max amount of data we can reassemble
       
   925 	// const TUint KTinyTPRemoteSegmentSize=8: Remote machine is unable
       
   926 	// to reassemble more data than this.
       
   927 	if ((ret=iControlSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone)
       
   928 		return ret;
       
   929 #ifdef __TRACEWIN__
       
   930 	LOG(Log::Printf(_L("IRLAN	Control channel connect on SLSAP=%d,DLSAP=%d\r\n"),
       
   931 	  home,iIrlanControlPortNum));
       
   932 #endif
       
   933 	return iControlSock->Connect(addr);
       
   934 }
       
   935 
       
   936 TInt CIrlanControlEngine::DoDataConnect()
       
   937 {
       
   938 	TSockAddr addr;
       
   939 	// Set home port number.
       
   940 	TUint8 home=KIrlanHomeDataPort;
       
   941 	addr.SetPort(home);
       
   942 	TInt ret=iDataSock->SetLocalName(addr);
       
   943 	if (ret!=KErrNone)
       
   944 		return ret;
       
   945 	addr.SetPort(TUint8(iIrlanDataPortNum));
       
   946 	// Enable segmentation/reassembly.
       
   947 	TPckgBuf<TUint> param(1518);	// Set segmentation/reassembly size
       
   948 	if ((ret=iDataSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone)
       
   949 		return ret;
       
   950 #ifdef __TRACEWIN__
       
   951 	LOG(Log::Printf(_L("IRLAN	Control channel connect on SLSAP=%d,DLSAP=%d\r\n"),
       
   952 	  home,iIrlanDataPortNum));
       
   953 #endif
       
   954 	return iDataSock->Connect(addr);
       
   955 }
       
   956 
       
   957 //######################################################################################
       
   958 
       
   959 /**
       
   960 Constructor.
       
   961 @param aCIrlan A pointer to CIrlanControlEngine object.
       
   962 */
       
   963 CIrlanControlEngineTimers::CIrlanControlEngineTimers(CIrlanControlEngine *aCIrlan)
       
   964 {
       
   965 	__DECLARE_NAME(_S("CIrlanControlEngineTimers"));
       
   966 	iIrlanControlEngine=aCIrlan;
       
   967 	iIrlanControlEngineTimerH=NULL;
       
   968 }
       
   969 
       
   970 /**
       
   971 Destructor.
       
   972 */
       
   973 CIrlanControlEngineTimers::~CIrlanControlEngineTimers()
       
   974 {
       
   975 	if (iIrlanControlEngineTimerH)
       
   976 		StopIrlanControlEngineTimer();
       
   977 }
       
   978 
       
   979 /**
       
   980 Initialise the value of iIrlanControl for static member functions
       
   981 @param aCIrlan A pointer to CIrlanControlEngine object.
       
   982 @return A pointer to CIrlanControlEngineTimers class.
       
   983 */
       
   984 CIrlanControlEngineTimers *CIrlanControlEngineTimers::NewL(CIrlanControlEngine *aCIrlan)
       
   985 {
       
   986 	return new (ELeave) CIrlanControlEngineTimers(aCIrlan);
       
   987 }
       
   988 
       
   989 /**
       
   990 Invoked to start the Internal Socket timer Can either complete as a call back to the
       
   991 static CIrlanControlEngine::IrlanControlEngineTimerExpired or can cancel.
       
   992 @param aCallBack Encapsulates a general call-back function.
       
   993 @param aTimeout Time out period
       
   994 */
       
   995 void CIrlanControlEngineTimers::StartIrlanControlEngineTimer(TCallBack aCallBack,TInt aTimeout)
       
   996 {
       
   997 	if (iIrlanControlEngineTimerH)
       
   998 		StopIrlanControlEngineTimer();
       
   999 	iIrlanControlEngineTimer.Set(aCallBack);
       
  1000 	iIrlanControlEngineTimerH=&iIrlanControlEngineTimer;
       
  1001 	IrlanTimer::Queue(aTimeout,iIrlanControlEngineTimer);
       
  1002 }
       
  1003 
       
  1004 /**
       
  1005 Invoked to stop a previously queued Internal Socket timer
       
  1006 */
       
  1007 void CIrlanControlEngineTimers::StopIrlanControlEngineTimer()
       
  1008 {
       
  1009 	if (iIrlanControlEngineTimerH)
       
  1010 		IrlanTimer::Remove(iIrlanControlEngineTimer);
       
  1011 	iIrlanControlEngineTimerH=NULL;
       
  1012 }
       
  1013 
       
  1014 void CIrlanControlEngineTimers::DoIrlanControlEngineTimerExpired()
       
  1015 {
       
  1016 	iIrlanControlEngineTimerH=NULL;
       
  1017 }