?? gsdpserver.cpp
字號:
// gsdpserver.cpp
//
// Copyright (c) 2000 Symbian Ltd. All rights reserved.
#include "gsdpserver.h"
#include <ecom\ecom.h>
#include <e32math.h>
#include <e32std.h>
void PanicServer(TInt aPanic)
{
_LIT(KPanicCategory,"GSDP Server");
User::Panic(KPanicCategory, aPanic);
}
void CGsdpScheduler::TServerStart::SignalL()
//
// Signal the owning thread that the server has started successfully
// This may itself fail
//
{
RThread starter;
User::LeaveIfError(starter.Open(iId));
starter.RequestComplete(iStatus,KErrNone);
starter.Close();
}
/*
class CGsdpScheduler
*/
TInt CGsdpScheduler::LaunchFromClient()
{
TRequestStatus started;
TServerStart start(started);
const TUidType serverUid(KNullUid,KNullUid,KNullUid);
#ifdef __WINS__
//
// To deal with the unique thread (+semaphore!) naming in EPOC,
// and that we may be trying to restart a server that has just
// exited we attempt to create a unique thread name for the
// server. This uses Math::Random() to generate a 32-bit random
// number for the name
//
TName name(KGsdpServerName);
name.AppendNum(Math::Random(),EHex);
RThread server;
TInt r=server.Create(name,ThreadFunction,
KDefaultStackSize*2, KMinHeapSize, 100000,
&start, EOwnerProcess);
#else
//
// EPOC is easy, we just create a new server process. Simultaneous
// launching of two such processes should be detected when the
// second one attempts to create the server object, failing with
// KErrAlreadyExists.
//
RProcess server;
TInt r=server.Create(KGsdpServerExe,start.AsCommand(),serverUid);
#endif
if (r!=KErrNone)
return r;
TRequestStatus died;
server.Logon(died);
if (died!=KRequestPending)
{
// logon failed - server is not yet running, so cannot have terminated
User::WaitForRequest(died); // eat signal
server.Kill(0); // abort startup
server.Close();
return died.Int();
}
//
// logon OK - start the server
server.Resume();
User::WaitForRequest(started,died); // wait for start or death
if (started==KRequestPending)
{
// server has died, never made it to the startup signal
server.Close();
return died.Int();
}
//
// server started (at last). Cancel and consume the death-notification
// before reporting success
server.LogonCancel(died);
server.Close();
User::WaitForRequest(died); // eat the signal (from the cancel)
return KErrNone;
}
#ifdef __WINS__
TInt CGsdpScheduler::ThreadFunction(TAny* aThreadParms)
{
// get a handle to our code to prevent yank on client death
RLibrary lib;
lib.Load(_L("gsdp.dll")); // this ought to work, so no error handling
// go with the thread
return ThreadStart(*static_cast<TServerStart*>(aThreadParms));
}
#endif
EXPORT_C TInt CGsdpScheduler::ThreadStart(TServerStart& aStart)
{
// get cleanup stack
CTrapCleanup* cleanup=CTrapCleanup::New();
#ifdef _DEBUG
TRAPD(terr,
for(TInt i=0; i< 20; i++)
CleanupStack::PushL((TAny*)NULL);
CleanupStack::Pop(20);
);
#endif
__UHEAP_MARK;
// initialize all up to and including starting scheduler
TInt err = KErrNoMemory;
if (cleanup)
{
TRAP(err, ConstructL(aStart));
delete cleanup;
}
__UHEAP_MARKEND;
return err;
}
void CGsdpScheduler::ConstructL(TServerStart& aStart)
{
// construct active scheduler
CGsdpScheduler* self=new(ELeave) CGsdpScheduler;
CleanupStack::PushL(self);
CActiveScheduler::Install(self);
// construct server
self->iServer=new(ELeave) CGsdpServer;
self->iServer->ConstructL();
// Let the client know we've started OK
aStart.SignalL();
CActiveScheduler::Start();
// Destroy the scheduler
CleanupStack::PopAndDestroy(self);
}
CGsdpScheduler::~CGsdpScheduler()
{
delete iServer;
}
void CGsdpScheduler::Error(TInt /*aError*/) const
{
__DEBUGGER();
PanicServer(EErrorFromNonClientObject);
}
/*
class CGsdpServer
*/
// construct
CGsdpServer::CGsdpServer()
: CServer(0, ESharableSessions)
{
}
void CGsdpServer::ConstructL()
{
// construct receive queue
iReceiveQueue= CGsdpReceiveQueue::NewL(*this);
// construct shutdown timer
iShutdown=new(ELeave) CGsdpDelayedShutdown();
iShutdown->ConstructL();
// construct port allocator
iPortAllocator=new(ELeave) CGsdpPortAllocator;
iPortAllocator->ConstructL();
// Initialise the protocol info
InitProtocolsL();
iProtoUpdater = CGsdpProtocolUpdater::NewL(*this);
// identify ourselves and open for service
StartL(KGsdpServerName);
// initiate shut down unless we get client connections
iShutdown->Start();
}
void CGsdpServer::InitProtocolsL()
/**
Initialise the server protocol information structures and
instantiate the loopback protocol.
*/
{
REComSession::ListImplementationsL(KGdpProtocolImpl, iProtocolInfo);
CGsdpGdpAdapter* adapter = CGsdpGdpAdapter::NewL(*this);
CleanupStack::PushL(adapter);
CGdpSession* loop = CGdpSession::NewL(KGdpLoopbackUid);
adapter->SetProtocolL(loop); // Takes ownership before leaving
User::LeaveIfError(iAdapters.Append(adapter));
CleanupStack::Pop(adapter);
}
void CGsdpServer::UpdateProtocolInfo()
{
RImplInfoPtrArray imps;
TRAPD(err,REComSession::ListImplementationsL(KGdpProtocolImpl, imps));
if(err == KErrNone)
{
iProtocolInfo.ResetAndDestroy();
iProtocolInfo = imps;
}
else
imps.ResetAndDestroy();
}
CGsdpServer::~CGsdpServer()
{
iAdapters.ResetAndDestroy();
iProtocolInfo.ResetAndDestroy();
delete iReceiveQueue;
delete iPortAllocator;
delete iShutdown;
delete iProtoUpdater;
}
// from CServer
CSharableSession* CGsdpServer::NewSessionL(const TVersion& /* aVersion */) const
{
CGsdpSession* session=new(ELeave) CGsdpSession();
CleanupStack::PushL(session);
session->ConstructL(*const_cast<CGsdpServer*>(this));
CleanupStack::Pop(session);
const_cast<CGsdpServer*>(this)->IncrementSessions();
return session;
}
TInt CGsdpServer::RunError(TInt aErr)
/**
Handle leaves from ServiceL.
Any leave from a ServiceL() will land up here.
*/
{
// if it's a bad descriptor, panic the client
if (aErr==KErrBadDescriptor) // client had a bad descriptor
{
PanicClient(EBadDescriptor);
}
// anyway, complete the outstanding message
Message().Complete(aErr);
ReStart(); // really means just continue reading client requests
return KErrNone;
}
// Protocol support
TInt CGsdpServer::CountProtocols()
/**
Return a count of the available protocol implementations.
*/
{
return iProtocolInfo.Count();
}
void CGsdpServer::GetProtocolInfoL(TInt aProto, TGdpProtocolInfo& aInfo)
{
if(aProto < 0 || aProto >= iProtocolInfo.Count())
User::Leave(KErrArgument);
aInfo.iUid = iProtocolInfo[aProto]->ImplementationUid();
aInfo.iDisplayName = iProtocolInfo[aProto]->DisplayName();
TLex8 lexer(iProtocolInfo[aProto]->OpaqueData());
User::LeaveIfError(lexer.Val(aInfo.iNetworked));
}
CGsdpGdpAdapter* CGsdpServer::GetProtocolL(TUid aProtocol)
/**
Returns the protocol adapter for the specified protocol.
Leaves if there is a problem.
*/
{
// Check if we already have an adaptor
// TODO: Use Find()?
TInt i;
for(i=0; i < iAdapters.Count(); i++)
{
if(iAdapters[i]->ProtocolUid() == aProtocol)
{
return iAdapters[i];
}
}
// if not, then create one
CGsdpGdpAdapter* adapter = CGsdpGdpAdapter::NewL(*this);
CleanupStack::PushL(adapter);
CGdpSession* protocol = CGdpSession::NewL(aProtocol);
adapter->SetProtocolL(protocol);
User::LeaveIfError(iAdapters.Append(adapter));
CleanupStack::Pop(adapter);
return adapter;
}
TUint32 CGsdpServer::MyNextPort()
/**
Return the next port.
*/
{
return iPortAllocator->NextPortId();
}
/**
session count support
*/
void CGsdpServer::IncrementSessions()
{
iSessionCount++;
iShutdown->Cancel();
}
void CGsdpServer::DecrementSessions()
{
iSessionCount--;
if (iSessionCount>0)
return;
iShutdown->Start();
}
// receive queue support
CGsdpSession* CGsdpServer::SessionForPacket(const TGsdpPacket& aPacket)
{
CSharableSession* session;
// iterate through sessions with non-zero port id
iSessionIter.SetToFirst();
for (session=iSessionIter++; session; session=iSessionIter++)
{
if (static_cast<CGsdpSession*>(session)->GetMyPort()==0)
continue;
if (static_cast<CGsdpSession*>(session)->CanReceivePacket(aPacket))
break;
}
if (session)
return static_cast<CGsdpSession*>(session);
// iterate through sessions with zero port id
iSessionIter.SetToFirst();
for (session=iSessionIter++; session; session=iSessionIter++)
{
if (static_cast<CGsdpSession*>(session)->GetMyPort()!=0)
continue;
if (static_cast<CGsdpSession*>(session)->CanReceivePacket(aPacket))
break;
}
return static_cast<CGsdpSession*>(session);
}
// utility
void CGsdpServer::PanicClient(TInt aPanic) const
{
// let's have a look before we panic the client
__DEBUGGER()
// ok, go for it
const_cast<RThread&>(Message().Client()).Panic(_L("GSDP-Server"),aPanic);
}
/*
class CGsdpProtocolUpdater
*/
CGsdpProtocolUpdater* CGsdpProtocolUpdater::NewL(CGsdpServer& aServer)
{
CGsdpProtocolUpdater* self = new (ELeave) CGsdpProtocolUpdater(aServer);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CGsdpProtocolUpdater::CGsdpProtocolUpdater(CGsdpServer& aServer)
: CActive(EPriorityLow), iServer(aServer)
{
}
void CGsdpProtocolUpdater::ConstructL()
{
iEcomSession = REComSession::OpenL();
CActiveScheduler::Add(this);
Start();
}
CGsdpProtocolUpdater::~CGsdpProtocolUpdater()
{
Cancel();
iEcomSession.Close();
}
void CGsdpProtocolUpdater::Start()
{
iEcomSession.NotifyOnChange(iStatus);
SetActive();
}
void CGsdpProtocolUpdater::RunL()
{
if(iStatus == KErrNone)
{
iServer.UpdateProtocolInfo();
}
Start();
}
void CGsdpProtocolUpdater::DoCancel()
{
iEcomSession.CancelNotifyOnChange(iStatus);
}
/*
class CGsdpDelayedShutdown
*/
CGsdpDelayedShutdown::CGsdpDelayedShutdown()
: CActive(0)
{
}
void CGsdpDelayedShutdown::ConstructL()
{
CActiveScheduler::Add(this);
User::LeaveIfError(iTimer.CreateLocal());
}
CGsdpDelayedShutdown::~CGsdpDelayedShutdown()
{
Cancel();
iTimer.Close();
}
void CGsdpDelayedShutdown::Start()
{
iTimer.After(iStatus, KGsdpShutdownInterval);
SetActive();
}
void CGsdpDelayedShutdown::DoCancel()
{
iTimer.Cancel();
}
void CGsdpDelayedShutdown::RunL()
{
CActiveScheduler::Stop();
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -