Sorry, I have not seen this thread for a while.
I do not really want to find out reliable ways to share unsharable objects between threads (you found that RCommServ does not tolerate ShareAuto), and then reliably keep data flowing between them.
I use a pair of active objects, where one of them is just a "skeleton" actually:
Code:
// HelperActive.h
#ifndef __HELPER_ACTIVE_H__
#define __HELPER_ACTIVE_H__
class MHelperObserver
{
public:
virtual void HelperRunL()=0;
virtual void HelperDoCancel()=0;
};
#include <e32base.h>
class CHelperActive : public CActive
{
public:
CHelperActive(MHelperObserver &aObserver);
~CHelperActive();
void SetActive();
void DoCancel();
void RunL();
private:
MHelperObserver &iObserver;
};
#endif
Code:
// HelperActive.cpp
#include "HelperActive.h"
CHelperActive::CHelperActive(MHelperObserver &aObserver) : CActive(EPriorityStandard)
,iObserver(aObserver)
{
CActiveScheduler::Add(this);
}
CHelperActive::~CHelperActive()
{
Cancel();
}
void CHelperActive::DoCancel()
{
iObserver.HelperDoCancel();
}
void CHelperActive::RunL()
{
iObserver.HelperRunL();
}
void CHelperActive::SetActive()
{
CActive::SetActive();
}
so it simply makes available its iStatus and SetActive to its owner and invokes a RunL and a DoCancel-like method using the MHelperObserver mixin.
Then an actual class using this is
Code:
CTCPClientActive::CTCPClientActive(CSocketStore &aSocketStore) : CActive(EPriorityStandard), iSocketStore(aSocketStore)
{}
CTCPClientActive* CTCPClientActive::NewL(CSocketStore &aSocketStore,TUint32 aAddress,TUint16 aPort)
{
CTCPClientActive* self = new(ELeave) CTCPClientActive(aSocketStore);
CleanupStack::PushL(self);
self->ConstructL(aAddress,aPort);
CleanupStack::Pop();
return self;
}
void CTCPClientActive::ConstructL(TUint32 aAddress,TUint16 aPort)
{
CActiveScheduler::Add(this);
iSendBuf=CBufFlat::NewL(1);
iRecvBuf=CBufFlat::NewL(1);
iHelper=new(ELeave)CHelperActive(*this);
User::LeaveIfError(iSocket.Open(iSocketStore.iSocketServ,KAfInet,KSockStream,KProtocolInetTcp,iSocketStore.iConnection));
iInetAddr.SetAddress(aAddress);
iInetAddr.SetPort(aPort);
iSocket.Connect(iInetAddr,iStatus);
SetActive();
iSendState=ESendConnecting;
iSocketStore.iClients.InsertInAddressOrderL(this); // do not leave after this line (ConsturctL: 'this' is also on the Cleanup Stack)
}
CTCPClientActive::~CTCPClientActive()
{
Cancel();
delete iHelper;
iSocket.Close();
delete iSendBuf;
delete iRecvBuf;
}
void CTCPClientActive::DoCancel()
{
switch(iSendState)
{
case ESendConnecting:
iSocket.CancelConnect();
break;
case ESendSend:
iSocket.CancelWrite();
break;
}
}
void CTCPClientActive::RunL()
{
if(iStatus!=KErrNone)
{
...
}
if (iStatus == KErrNone)
{
switch(iSendState)
{
case ESendConnecting:
StartRecv();
iSendState=ESendIdle; // server-side sends the first message (Hello)
break;
case ESendSend:
iSendState=ESendIdle;
iSendBuf->Delete(0,iSendData.Size());
TrySend();
break;
}
}
}
void CTCPClientActive::HelperDoCancel()
{
switch(iRecvState)
{
case ERecvRecv:
iSocket.CancelRecv();
break;
}
}
void CTCPClientActive::HelperRunL()
{
if(iHelper->iStatus!=KErrNone)
{
...
}
if (iHelper->iStatus == KErrNone)
{
switch(iRecvState)
{
case ERecvRecv:
iRecvBuf->InsertL(iRecvBuf->Size(),iRecvData);
iRecvBuf->Delete(0,iTransfer->ReceiveL(iRecvBuf->Ptr(0)));
if(iTransfer->state==TX_CLOSING && iSendState==ESendIdle)
ShutDownL(_L("TX_CLOSING"));
else
StartRecv();
break;
}
}
}
void CTCPClientActive::StartRecv()
{
iSocket.RecvOneOrMore(iRecvData,0,iHelper->iStatus,iSockXfrLength);
iHelper->SetActive();
iRecvState=ERecvRecv;
}
void CTCPClientActive::SendL(const TDesC8 &aMessage)
{
iSendBuf->InsertL(iSendBuf->Size(),aMessage);
TrySend();
}
void CTCPClientActive::TrySend()
{
if(iSendState!=ESendIdle)
return;
if(iSendBuf->Size()==0)
{
if(iTransfer->state==TX_CLOSING)
ShutDownL(_L("TX_CLOSING"));
return;
}
iSendData.Set(iSendBuf->Ptr(0));
iSocket.Write(iSendData,iStatus);
SetActive();
iSendState=ESendSend;
}
"main" class connects and sends data (when available), while the "Helper" part is receiving data on the same RSocket object all the time.