⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gsdpserver.cpp

📁 Symbian mobile os C++ GSDP编程
💻 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 + -