/*
* 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 the License "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:
*
*/
/**
@file
*/
#include "randsvr.h"
#include "randcliserv.h"
#include "sha1shim.h"
#include <e32math.h>
#include "randsvrimpl.h"
//const TInt KFastTickTimer=1000000; // These are testing numbers!
//const TInt KSlowTickTimer=30000000;
const TInt KThreshold=1024;
const TInt KFastTickTimer=30000000; // These are the real numbers!
const TInt KSlowTickTimer=0x7fffffff;
using namespace CryptoSpi;
void SignalClient()
//
// Signal the owning thread that the server has started successfully
// This may itself fail
//
{
RProcess::Rendezvous(KErrNone);
}
TInt RunRandomServer(TAny* /*aUnused*/)
{
__UHEAP_MARK;
CTrapCleanup* cleanup=CTrapCleanup::New();
if (!cleanup)
{
return KErrNoMemory;
}
TInt ret = User::RenameThread(KRandomServerName);
__ASSERT_ALWAYS(ret==KErrNone,User::Panic(KRandomServerName,KErrServerTerminated));
if (CRandomScheduler::New())
return KErrNoMemory;
CRandomServer* random(0);
TRAP(ret, random = CRandomServer::NewL());
if (ret != KErrNone)
return ret;
random->Start(KRandomServerName);
// Initialisation complete, now signal the client
SignalClient();
CRandomScheduler::Start();
delete random;
delete cleanup;
__UHEAP_MARKEND;
return KErrNone;
}
TBool CRandomScheduler::New(void)
{
CRandomScheduler* rs;
rs=new CRandomScheduler;
CRandomScheduler::Install(rs);
return (rs == NULL);
}
void CRandomScheduler::Error(TInt /*aError*/) const
{
User::Panic(KRandomServerName, 3);
}
CRandomServer::CRandomServer(void) : CServer2(EPriorityLow)
{
}
CRandomServer::~CRandomServer(void)
{
// This should never happen....but in case it does:
delete iHash;
delete iTicker;
delete iPool;
}
CRandomServer* CRandomServer::NewL(void)
{
CRandomServer* self = new (ELeave) CRandomServer;
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CRandomServer::ConstructL(void)
{
iPool=new (ELeave) TUint8[KRandomPoolSize];
iHash=CSHA1Shim::NewL();
iPoolIn=0;
iPoolOut=0;
iTicker=CPeriodic::NewL(EPriorityLow);
TCallBack callback(Tick,this);
iTicker->Start(KFastTickTimer,KFastTickTimer,callback); // **** these figures might need tweaking!
iQuality=0;
iFast=ETrue;
}
TInt CRandomServer::Tick(TAny* aServer)
{
CRandomServer* svr=(CRandomServer*)aServer;
svr->Stir();
svr->iQuality+=30;
if (svr->iFast)
{
if (svr->iQuality>KThreshold)
{
TCallBack callback(Tick,svr);
svr->iTicker->Cancel();
svr->iTicker->Start(KSlowTickTimer,KSlowTickTimer,callback); // **** these figures might need tweaking!
svr->iFast=EFalse;
}
}
if (svr->iQuality>(KRandomPoolSize<<3))
{
svr->iQuality=(KRandomPoolSize<<3);
}
return ETrue;
}
CSession2* CRandomServer::NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
{
return CRandomSession::NewL(const_cast<CRandomServer*>(this));
//CRandomSession::NewL(CONST_CAST(CRandomServer*,this),Message().Client());
}
TPtrC8 CRandomServer::GetRandom(void)
{
TPtr8 res(&iPool[iPoolOut],iHash->HashSize(),iHash->HashSize());
iPoolOut+=iHash->HashSize();
if ((iPoolOut+iHash->HashSize())>KRandomPoolSize)
{
iPoolOut=0;
}
return iHash->Hash(res);
}
CMessageDigest* CRandomServer::Hash(void) const
{
return iHash;
}
void CRandomServer::Stir(void)
{
TInt rnd;
rnd=Math::Random();
TPtrC8 r((TUint8*)&rnd,sizeof(TInt));
iHash->Hash(r);
TPtr8 dest(&iPool[iPoolIn],iHash->HashSize());
dest.Copy(iHash->Hash(dest));
iPoolIn+=iHash->HashSize();
if ((iPoolIn+iHash->HashSize())>KRandomPoolSize)
{
iPoolIn=0;
}
}
CRandomSession* CRandomSession::NewL(CRandomServer* aServer)
{
CRandomSession* self;
self=new (ELeave) CRandomSession(aServer);
return self;
}
CRandomSession::CRandomSession(CRandomServer* aServer) : CSession2(), iServer(aServer)
{
}
CRandomSession::~CRandomSession(void)
{
}
void CRandomSession::ServiceL(const RMessage2& aMessage)
{
switch (aMessage.Function())
{
case KRandomRequest:
{
TInt ret = FillBuffer(aMessage);
aMessage.Complete(ret);
break;
}
default:
aMessage.Complete(KErrNotSupported);
break;
};
}
TInt CRandomSession::FillBuffer(const RMessage2& aMessage)
{
TInt length = aMessage.Int1();
iServer->iQuality -= length;
if (iServer->iQuality<0)
{
iServer->iQuality=0;
}
if (!iServer->iFast)
{
if (iServer->iQuality<KThreshold)
{
TCallBack callback(CRandomServer::Tick,iServer);
iServer->iTicker->Cancel();
iServer->iTicker->Start(KFastTickTimer,KFastTickTimer,callback); // **** these figures might need tweaking!
iServer->iFast=ETrue;
}
}
TBuf8<KRandomBlockSize> buf(0);
iServer->Stir();
TInt i;
TInt hashsize=iServer->Hash()->HashSize();
for (i=0; i+hashsize < length; i+=hashsize)
{
buf.Append(iServer->GetRandom());
iServer->Stir();
}
TPtrC8 ptr(iServer->GetRandom().Ptr(), length-i);
buf.Append(ptr);
TRAPD(ret, aMessage.WriteL(0, buf));
return ret;
}
GLDEF_C TInt E32Main(void)
{
return RunRandomServer(NULL);
}