--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/cstdlib/USTLIB/POSIXIF.CPP Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,1667 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// Client interface to the CPosixServer
+//
+//
+
+#include "POSIXIF.H"
+#include "LTIME.H"
+#include "LPOSIX.H"
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <sys/serial.h>
+#include <sys/wait.h>
+
+
+#ifdef _DEBUG
+#define DebugPrint RDebug::Print
+#else
+inline void DebugPrint(const TDesC&, ...) {}
+#endif
+
+// RPosixSession
+//
+// The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
+// in p[1]. The result is written back into the PosixParams.retval field.
+
+int RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams) const
+ {
+ return SendReceive(aFunction,TIpcArgs(&anErrno,&aParams));
+ }
+
+void RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams, TRequestStatus& aStatus) const
+ {
+ SendReceive(aFunction,TIpcArgs(&anErrno,&aParams),aStatus); // asynchronous request
+ }
+
+void RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg,TRequestStatus &aStatus) const
+ {
+ RSessionBase::SendReceive(aFunction,aArg,aStatus);
+ }
+TInt RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg) const
+ {
+ return RSessionBase::SendReceive(aFunction,aArg);
+ }
+
+TVersion RPosixSession::Version()
+ {
+ return TVersion(KCPosixMajorVersionNumber,KCPosixMinorVersionNumber,0);
+ }
+
+TInt RPosixSession::Connect (TDesC& aServerName)
+ {
+ TVersion version=Version();
+ return CreateSession(aServerName,version,1+3); // 3 extra message slots for pipes
+ }
+
+TInt RPosixSession::Connect ()
+ {
+ TBuf<80> serverName;
+ PosixServerName(serverName);
+ return CreateSession(serverName,Version(),1);
+ }
+
+// CPosixServer support functions exported from ESTLIB.DLL
+
+#if defined(__WINS__)
+
+// simple scheme to provide pretend processes on WINS
+
+extern "C" void getcwd(char*,int);
+typedef void (*FUNC)();
+
+static int id=1;
+EXPORT_C void NewProcessId ()
+ {
+ id += 10;
+ }
+
+static FUNC procFn;
+EXPORT_C void NextProcessFn (TAny* aFn)
+ {
+ procFn=(FUNC)aFn;
+ }
+
+TInt threadhelper (TAny* aFn)
+ {
+ CTrapCleanup::New();
+ FUNC f=(FUNC)aFn;
+ (*f)();
+ return 0;
+ }
+TInt processhelper (TAny*)
+ {
+ // Do the MCRT0.OBJ things straight away
+ SpawnPosixServerThread();
+ char wd[80];
+ getcwd(wd, sizeof(wd)); // connect to CPosixServer
+ return threadhelper(procFn);
+ }
+#endif // __WINS__
+_LIT(SERVER_FORMAT,"Posix-%d");
+_LIT(SERVER_MATCH, "Posix-*");
+
+EXPORT_C void PosixServerName(TDes& aBuffer)
+//
+// Construct the name of the CPosixServer for this process
+//
+ {
+ TProcessId id=RProcess().Id();
+ aBuffer.Format(SERVER_FORMAT,*REINTERPRET_CAST(int*,&id));
+ }
+
+struct rendezvous
+ {
+ RThread iCaller;
+ TRequestStatus* iStatus;
+ };
+
+EXPORT_C TInt SpawnPosixServerThread ()
+//
+// Try to start a PosixServer thread, assuming there isn't one already
+//
+ {
+ RPosixSession probe;
+ TInt err=probe.Connect();
+ probe.Close();
+ if (err==KErrNone)
+ return KErrNone; // server already exists
+ TBuf<80> serverName;
+ PosixServerName(serverName);
+ TRequestStatus status(KRequestPending);
+ struct rendezvous rv;
+ rv.iCaller.Duplicate(RThread(),EOwnerProcess);
+ rv.iStatus=&status;
+ RThread server;
+ err=server.Create(serverName,CPosixServer::ThreadFunction,0x2000,NULL,&rv);
+ if (err==KErrNone)
+ {
+ server.Resume();
+ User::WaitForRequest(status);
+ err=status.Int();
+ server.Close();
+ }
+ rv.iCaller.Close();
+ return err;
+ }
+
+EXPORT_C TInt InstallPosixServerActiveObject (TInt aPriority)
+ {
+ TRAPD(err, CPosixServer::InitL(aPriority));
+ return err;
+ }
+
+void CPosixServer::InitL(TInt aPriority)
+//
+// Construct and install a CPosixServer active object
+//
+ {
+ CPosixServer *pS=new(ELeave) CPosixServer(aPriority);
+ CleanupStack::PushL(pS);
+ TBuf<80> serverName;
+ PosixServerName(serverName);
+
+ User::LeaveIfError(pS->iFs.Connect());
+
+ pS->iFids.InitL();
+
+ // search for parent process
+ pS->FindParentL();
+
+ // set up default fids
+ pS->DefaultConsoleL();
+
+ DebugPrint(_L("Starting CPosixServer\n"));
+ pS->StartL(serverName);
+ CleanupStack::Pop(pS);
+// Leave pS on the clean up stack for the calling routine to clean up normally on
+// Active Scheduler shutdown or in a failure case where the scheduler does not
+// start due to an error.
+
+ }
+
+// CPosixServer
+
+CPosixServer::CPosixServer(TInt aPriority)
+ : CServer2(aPriority)
+ {
+ __DECLARE_NAME(_S("CPosixServer"));
+ }
+
+TInt CPosixServer::ThreadFunction(TAny* aPtr)
+//
+// Create and run an active scheduler containing a CPosixServer
+//
+ {
+ CTrapCleanup* TheTrapCleanup=CTrapCleanup::New();
+
+ RLibrary stdlib;
+ stdlib.Load(_L("estlib")); // workaround for RAM-loaded EXE calling RAM-loaded DLL
+
+ struct rendezvous* rvp = (struct rendezvous *)aPtr;
+ TInt ret=KErrNone;
+ // start scheduler and server
+ CActiveScheduler *pA=new CActiveScheduler;
+ if (pA!=NULL)
+ {
+ CActiveScheduler::Install(pA);
+ ret=InstallPosixServerActiveObject();
+ }
+ // signal to the caller that we've started (or failed!)
+ rvp->iCaller.RequestComplete(rvp->iStatus,ret);
+ if (ret==KErrNone)
+ {
+ // start fielding requests from clients
+ CActiveScheduler::Start();
+ }
+ // finished
+ delete TheTrapCleanup;
+ return(KErrNone);
+ }
+
+CSession2* CPosixServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
+ {
+ TBool r=User::QueryVersionSupported(RPosixSession::Version(),aVersion);
+ if (!r)
+ User::Leave(KErrNotSupported);
+
+ RProcess clientProcess;
+ RThread clientThread;
+ User::LeaveIfError(aMessage.Client(clientThread));
+ CleanupClosePushL(clientThread);
+ User::LeaveIfError(clientThread.Process(clientProcess));
+ TProcessId clientId = clientProcess.Id();
+ clientProcess.Close();
+ CleanupStack::PopAndDestroy(1); //close thread
+
+ if (clientId!=RProcess().Id())
+ {
+ // A thread in a different process
+ if (iChildren==0)
+ User::Leave(KErrNotReady); // quick rejection
+
+ // We need an explicit CONST_CAST so that the CPosixRequest objects have a
+ // mutable reference to the CPosixServer which holds the shared data structures
+ return new(ELeave) CPosixIPCSession(CONST_CAST(CPosixServer&,*this));
+ }
+ // A thread in the same process
+ return new(ELeave) CPosixSession(CONST_CAST(CPosixServer&,*this));
+ }
+
+void CPosixServer::ServerPanic (TPosixServerPanic aPanic)
+ {
+ _LIT(KPosixServerPanic, "Posix server");
+ User::Panic(KPosixServerPanic,aPanic);
+ }
+
+void CPosixServer::FindParentL()
+ {
+ TFullName parent;
+ TPosixIPCPid pid;
+ TPosixIPCReply reply;
+
+ TProcessId id=RProcess().Id();
+ pid = *REINTERPRET_CAST(TUint*,&id); // my process id
+
+ TFindServer posixservers(SERVER_MATCH);
+ while (posixservers.Next(parent)==KErrNone)
+ {
+ DebugPrint(_L("Are you my mother, %S?"), &parent);
+ if (iParent.Connect(parent)!=KErrNone)
+ continue;
+ if (iParent.Request(PMAreYouMyMother,TIpcArgs(&pid, &reply))!=KErrNone)
+ {
+ iParent.Close();
+ continue;
+ }
+
+ // found parent
+ DebugPrint(_L("Found parent process %S"), &parent);
+
+ // Create any pipes that might be required
+ TUint mask=reply().iPipeMask;
+ CPipeChildDesc* pipes[3];
+ TInt i=0;
+ for (i=0; i<3; i++, mask>>=1)
+ {
+ pipes[i]=0;
+ if (mask&1)
+ {
+ CPipeChildDesc* pipe=new(ELeave) CPipeChildDesc(i,iParent);
+ pipes[i]=pipe;
+ pipe->PushLC();
+ }
+ }
+
+ // organise the necessary descriptors
+ TPtr env=HBufC::NewLC(reply().iEnvironmentSize)->Des();
+ TPtr cwd=HBufC::NewLC(reply().iWorkingDirectorySize)->Des();
+
+ // get the data from parent
+ TInt err=iParent.Request(PMHelloMum, TIpcArgs(&pid, &env, &cwd));
+
+ DebugPrint(_L("Environment string: %S"), &env);
+ DebugPrint(_L("Working directory: %S"), &cwd);
+
+ if(err!=KErrNone)
+ {
+ DebugPrint(_L("I've become an orphan"));
+ // release stuff
+ iParent.Close();
+ User::Leave(err);
+ break;
+ }
+ // apply to our process
+ iEnv.ConstructL(reply().iVarCount,env);
+ err=iFs.SetSessionPath(cwd);
+ User::LeaveIfError(err);
+
+ // free up the temporary descriptors
+ CleanupStack::PopAndDestroy(2);
+
+ // Attach the pipes!
+ for (i=0; i<3; i++)
+ {
+ iFids.Attach(i, pipes[i]);
+ if (pipes[i]!=0)
+ CleanupStack::Pop();
+ }
+ return;
+ }
+ DebugPrint(_L("Posix-%d is a top-level process"), pid());
+ User::LeaveIfError(PosixFilesystem::SetDefaultDir(iFs));
+ }
+
+int CPosixServer::POpen3(PosixParams* aParams, int& anErrno)
+ {
+ TInt err=KErrNoMemory;
+ //coverity[alloc_fn]
+ //coverity[assign]
+ CPosixProcess* proc= new CPosixProcess(*this);
+ if (proc!=0)
+ {
+ //coverity[leave_without_push]
+ err=iFids.Reserve(aParams->pint);
+ if (err==KErrNone)
+ {
+ TRAP(err,proc->POpen3L(aParams));
+ }
+ if (err==KErrNone)
+ {
+ DebugPrint(_L("POpen3 created process %d"), proc->iPid);
+ proc->iNextProcess=iChildren;
+ iChildren=proc;
+ return (int)proc->iPid; // success
+ }
+ delete proc;
+ iFids.Detach(aParams->pint);
+ }
+ return MapError(err, anErrno);
+ }
+
+CPosixRequest* CPosixServer::Waiters()
+ {
+ CPosixRequest* waiters=iWaitAnyQueue;
+ iWaitAnyQueue=0;
+ return waiters;
+ }
+
+// CPosixSession
+//
+// Each local thread gets one of these
+
+CPosixSession::CPosixSession(CPosixServer& aServer)
+ : iActive(aServer)
+ {
+ CActiveScheduler::Add(&iActive);
+ __DECLARE_NAME(_S("CPosixSession"));
+ }
+
+void CPosixSession::ServiceL(const RMessage2& aMessage)
+ {
+ iActive.Service(aMessage);
+ }
+
+// CPosixRequest
+//
+// An active object contained within the Session that handles the deferred completion
+// of asynchronous functions (e.g. read & write).
+
+CPosixRequest::CPosixRequest(CPosixServer& aServer)
+ : CActive(EPriorityStandard), iServer(aServer), iPtr(0,0)
+ {
+// iFile=0;
+// iNewF=0;
+// iNewFid=0;
+ }
+
+void CPosixRequest::Service(const RMessage2& aMessage)
+//
+// The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
+// in p[1]. The result is written back into the PosixParams.retval field.
+//
+ {
+ if (aMessage.Function() == PMcancel)
+ {
+ Cancel(); // Cancel in the active scheduler
+ if (iFile)
+ EndAsynch(KErrCancel); // Complete the cancelled request & clean up
+ aMessage.Complete(KErrNone);
+ return;
+ }
+
+ if (iFile!=0)
+ {
+ aMessage.Complete(KErrInUse);
+ return;
+ }
+ int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,aMessage.Ptr0()));
+ PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,aMessage.Ptr1()));
+ switch (aMessage.Function())
+ {
+
+ // Asynchronous functions need queuing, active objects etc.
+
+ case PMread:
+ case PMwrite:
+ case PMsendto:
+ case PMrecvfrom:
+ iPtr.Set((TText8*)params->ptr[0], params->len[0], params->len[0]);
+ // and fall through...
+ case PMfsync:
+ case PMconnect:
+ case PMshutdown:
+ {
+ TInt err=Fids().Asynch(params->fid,iFile);
+ if (!err)
+ {
+ QueueAsynch(aMessage); // start operation or queue if busy
+ return; // deferred completion through RunL
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+
+ case PMaccept:
+ {
+ TInt err=Fids().Asynch(params->fid,iFile);
+ if (!err)
+ {
+ iNewF=0;
+ iNewFid=Fids().Reserve(); // reserve a fid for the accepted socket
+ err=iNewFid;
+ if (iNewFid>=0)
+ {
+ QueueAsynch(aMessage); // start operation or queue if busy
+ return; // deferred completion through RunL
+ }
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+
+ case PMioctl:
+ case PMioctlN:
+ {
+ TInt err=Fids().Asynch(params->fid,iFile);
+ if (!err)
+ {
+ QueueAsynch(aMessage); // start operation or queue if busy
+ return; // deferred completion through RunL
+ }
+
+ aMessage.Complete(err); // Different calling convention
+ return;
+ }
+
+ // complicated synchronous functions which might do their own completion
+
+ case PMwaitpid:
+ {
+ // check for invalid options or if an invalid pid is specified. currently there is no
+ // support for process group id's so a pid less than -1 or equal to 0 is invalid
+ if((params->pint[1] & ~(WNOHANG|WUNTRACED))|| (params->pint[0] < -1) || (params->pint[0] ==0))
+ {
+ anErrno=EINVAL;
+ params->ret=-1;
+ break;
+ }
+ if (params->pint[0]==-1 && params->pint[1]==0) /* wait for any child */
+ {
+ iMessage=aMessage;
+ iServer.WaitForAnyChild(this);
+ return; // wait for the next child to die
+ }
+ CPosixProcess* child=iServer.Child(params->pint[0]);
+ if (child!=0)
+ {
+ if (child->IsAlive())
+ {
+ if (params->pint[1]&1) /* WNOHANG */
+ {
+ params->ret=0;
+ break;
+ }
+ iMessage=aMessage;
+ child->Queue(this);
+ return; // wait for the child to die
+ }
+ params->pint[0]=child->iExitReason;
+ params->ret=child->iPid;
+ iServer.Release(child);
+ }
+ else
+ {
+ anErrno=ECHILD;
+ params->ret=-1;
+ }
+ }
+ break;
+
+ // simple synchronous functions
+
+ case PMdup:
+ params->ret=Fids().dup(params->fid,anErrno);
+ break;
+ case PMdup2:
+ params->ret=Fids().dup2(params->fid,params->pint[0],anErrno);
+ break;
+ case PMopen:
+ {
+ const wchar_t* name = params->cwptr[0];
+ if ((L'C' == name[0]) && (L'O' == name[1]) && (L'M' == name[2]) && (L':' == name[4]) && ((name[3] >= L'1') && (name[3] <= L'9')) ||
+ (L'I' == name[0]) && (L'R' == name[1]) && (L'C' == name[2]) && (L'O' == name[3]) && (L'M' == name[4]) && (L':' == name[6]) && ((name[5] >= L'1') && (name[5] <= L'9')))
+ params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Cs());
+ else
+ params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Fs());
+
+ }
+ break;
+ case PMclose:
+ params->ret=Fids().userclose(params->fid,anErrno);
+ break;
+ case PMlseek:
+ params->ret=Fids().lseek(params->fid,params->pint[0],params->pint[1],anErrno);
+ break;
+ case PMfstat:
+ params->ret=Fids().fstat(params->fid,(struct stat*)params->ptr[0],anErrno);
+ break;
+ case PMgetcwd:
+// params->ret=(int)PosixFilesystem::getcwd(Fs(),params->ptr[0],params->len[0],anErrno);
+ params->ret=(int)PosixFilesystem::getcwd(Fs(),params->wptr[0],params->len[0],anErrno);
+ break;
+ case PMchdir:
+ params->ret=PosixFilesystem::chdir(Fs(),params->cwptr[0],anErrno);
+ break;
+ case PMmkdir:
+// params->ret=PosixFilesystem::mkdir(Fs(),params->cptr[0],params->pint[0],anErrno);
+ params->ret=PosixFilesystem::mkdir(Fs(),params->cwptr[0],params->pint[0],anErrno);
+ break;
+ case PMrmdir:
+ params->ret=PosixFilesystem::rmdir(Fs(),params->cwptr[0],anErrno);
+ break;
+ case PMchmod:
+ params->ret=PosixFilesystem::chmod(Fs(),params->cwptr[0],params->pint[0],anErrno);
+ break;
+ case PMunlink:
+ params->ret=PosixFilesystem::unlink(Fs(),params->cwptr[0],anErrno);
+ break;
+ case PMstat:
+ params->ret=PosixFilesystem::stat(Fs(),params->cwptr[0],(struct stat*)params->ptr[0],anErrno);
+ break;
+ case PMrename:
+ params->ret=PosixFilesystem::rename(Fs(), params->cwptr[0],params->cwptr[1],anErrno);
+ break;
+ case PMResolvePath:
+// params->ret=PosixFilesystem::ResolvePath(Fs(),
+// *(TParse*)params->ptr[0],params->cptr[0],(TDes*)params->ptr[1]);
+ params->ret=PosixFilesystem::ResolvePath(Fs(),
+ *(TParse*)params->ptr[0],params->cwptr[0],(TDes*)params->ptr[1]);
+ break;
+ case PMsocket:
+ params->ret=Fids().socket(params->pint[0],params->pint[1],params->pint[2],anErrno,Ss());
+ break;
+ case PMbind:
+ params->ret=Fids().bind(params->fid,params->addr,anErrno);
+ break;
+ case PMlisten:
+ params->ret=Fids().listen(params->fid,params->pint[0],anErrno);
+ break;
+ case PMsockname:
+ params->ret=Fids().sockname(params->fid,params->addr,params->pint[0],anErrno);
+ break;
+ case PMgetsockopt:
+ params->ret=Fids().getsockopt(params->fid,params->pint[0],params->pint[1],
+ params->ptr[0],params->lenp[0],anErrno);
+ break;
+ case PMsetsockopt:
+ params->ret=Fids().setsockopt(params->fid,params->pint[0],params->pint[1],
+ params->ptr[0],params->len[0],anErrno);
+ break;
+ case PMgetenv:
+ params->ret=(int)Env().getenv(params->cwptr[0]);
+ break;
+ case PMunsetenv:
+ Env().unsetenv(params->cwptr[0]); // no return value
+ break;
+ case PMsetenv:
+ params->ret=Env().setenv(params->cwptr[0],params->cwptr[1],params->pint[0],anErrno);
+ break;
+ case PMioctlcomplete:
+ params->ret=Fids().ioctlcomplete(params->fid,params->pint[0],params->ptr[0],*(REINTERPRET_CAST(TRequestStatus*, params->ptr[1])), anErrno);
+ break;
+ case PMTerminateProcess:
+ {
+ int status = params->fid;
+ RProcess().Kill(status);
+ }
+ break;
+ case PMpopen3:
+ params->ret=iServer.POpen3(params,anErrno);
+ break;
+ default:
+ aMessage.Complete(KErrNotSupported);
+ return;
+ }
+ // deal with completion of a synchronous request
+ aMessage.Complete(KErrNone);
+ }
+
+// Asynchronous requests
+//
+// 1. QueueAsynch() to get into the appropriate queue in the FileDesc
+// 2. FileDesc calls StartAsynch() when it's our turn
+// 3. StartAsynch() makes the relevant IO call and does SetActive()
+// 4a. RunL() handles the completion of the IO call and calls EndAsynch()
+// 4b. DoCancel() handles cancellation of the IO call, but doesn't call EndAsynch()
+// 5. EndAsynch() removes us from the FileDesc queue and completes iMessage
+//
+
+void CPosixRequest::QueueAsynch(const RMessage2& aMessage)
+//
+// Add this to the appropriate queue in the associated file
+//
+ {
+ iMessage=aMessage; // Suggested by AndrewT to avoid code duplication
+ iQueue=CFileDescBase::IOwriteQ;
+ switch (aMessage.Function())
+ {
+ case PMread:
+ case PMrecvfrom:
+ iQueue=CFileDescBase::IOreadQ;
+ break;
+ case PMioctl:
+ iQueue=CFileDescBase::IOioctlQ;
+ break;
+ case PMioctlN:
+ iQueue=CFileDescBase::IOioctlNQ;
+ break;
+ default:
+ // everything else uses the IOwriteQ, including Accept and Connect
+ break;
+ }
+
+ __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
+ iFile->AddLast(*this,iQueue);
+ }
+
+void CPosixRequest::StartAsynch()
+//
+// The request has reached the front of the queue and can now be actioned
+//
+ {
+ PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
+ switch (iMessage.Function())
+ {
+ case PMread:
+ {
+
+ //if we need to have a timer for this operation to cancel it later
+ if (iFile->TimedRead())
+ {
+ iFile->ReadIsTimed = ETrue;
+ TRAPD(tRes, {iFile->TimedMessage = CSerialTimer::NewL(iFile);});
+ if (tRes != KErrNone)
+ {
+ //we have a problem here
+ //basically, fake the async request completing with the returned error
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus * ps = &iStatus;
+ User::RequestComplete(ps, tRes);
+ return;
+ }
+
+ iFile->TimedMessage->IssueRequest();
+ }
+ else
+ iFile->ReadIsTimed = EFalse;
+
+ iFile->ReadWasCancelled = EFalse;
+
+ iFile->Read(iPtr,iStatus);
+
+ }
+ break;
+ case PMrecvfrom:
+ iFile->RecvFrom(iPtr,params->addr,params->pint[0],iStatus);
+ break;
+ case PMwrite:
+ iFile->Write(iPtr,iStatus);
+ break;
+ case PMsendto:
+ iFile->SendTo(iPtr,params->addr,params->pint[0],iStatus);
+ break;
+ case PMfsync:
+ iFile->Sync(iStatus);
+ break;
+ case PMconnect:
+ iFile->Connect(params->addr,iStatus);
+ break;
+ case PMshutdown:
+ iFile->Shutdown(params->pint[0],iStatus);
+ break;
+ case PMaccept:
+ iFile->Accept(iNewF,iStatus,Ss());
+ break;
+ case PMioctl:
+ iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
+ break;
+ case PMioctlN:
+ iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
+ break;
+ default:
+ EndAsynch(KErrGeneral);
+ return;
+ }
+ SetActive(); // for asynchronous completion via RunL
+ return;
+ }
+
+void CPosixRequest::RunL()
+//
+// The pending IO has completed, so handle the result
+//
+ {
+ __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
+ TInt completion=KErrNone;
+ int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,iMessage.Ptr0()));
+ PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
+ switch (iMessage.Function())
+ {
+ case PMread:
+ {
+ if (iFile->ReadIsTimed)
+ {
+ //need to stop the timer
+ delete iFile->TimedMessage;
+ iFile->TimedMessage = NULL;
+ iFile->ReadIsTimed = EFalse;
+ }
+
+ TInt err=iFile->ReadCompletion(iPtr, iStatus.Int());
+ if (err==0)
+ {
+ params->ret=iPtr.Length();
+ break;
+ }
+ //if the read was cancelled and we are to patch it due to me cancelling it
+
+ if (iFile->ReadWasCancelled)
+ {
+ err = ETIMEDOUT;
+ iFile->ReadWasCancelled = EFalse;
+ }
+
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+ case PMwrite:
+ {
+ TInt err=iFile->WriteCompletion(iPtr, iStatus.Int());
+ if (err==0)
+ {
+ params->ret=iPtr.Length();
+ break;
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+ case PMconnect:
+ case PMshutdown:
+ case PMfsync:
+ params->ret=MapError(iStatus.Int(),anErrno);
+ break;
+ case PMsendto:
+ {
+ TInt err=iFile->SendToCompletion(iPtr, iStatus.Int());
+ if (err==0)
+ {
+ params->ret=iPtr.Length();
+ break;
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+ case PMrecvfrom:
+ {
+ TInt err=iFile->RecvFromCompletion(params->ret, iStatus.Int());
+ if (err==0)
+ {
+ params->ret=iPtr.Length();
+ break;
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+ case PMaccept:
+ {
+ TInt err=iStatus.Int();
+ if (err)
+ Fids().Attach(iNewFid,0); // cancel the reservation
+ else
+ {
+ err=Fids().Attach(iNewFid,iNewF);
+ if (!err)
+ {
+ params->ret=iNewFid;
+ break; // so that we return the new fid
+ }
+ delete iNewF;
+ iNewF=0;
+ }
+ params->ret=MapError(err,anErrno);
+ }
+ break;
+
+ case PMioctlN:
+ {
+ completion=iStatus.Int(); // caller picks up completion explicitly
+ }
+ break;
+
+ case PMioctl:
+ {
+ completion=iStatus.Int(); // caller picks up completion explicitly
+// TInt err=iFile->IoctlCompletion(params->pint[0], ¶ms->ret, iStatus.Int());
+// params->ret=MapError(err,anErrno);
+ }
+ break;
+
+ default:
+ completion=KErrGeneral; // arrgh - I imagine that it's going to die if we get here...
+ break;
+ }
+ EndAsynch(completion);
+ }
+
+void CPosixRequest::EndAsynch(TInt aResult)
+//
+// finish an asynchronous operation and complete iMessage
+//
+ {
+ __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
+ iFile->Remove(*this,iQueue);
+ iFile->Close(); // balances the Dup() in CFileTable::Asynch(), may delete object!
+ iFile=0;
+ iMessage.Complete(aResult);
+ }
+
+
+void CPosixRequest::DoCancel()
+//
+// The pending IO has been cancelled, so cancel the outstanding request
+// Needs to deal with all of the cases in RunL, but doesn't call EndAsynch().
+// This is called from CActive::Cancel() only when the object is active, but
+// EndAsynch() needs to be called when the object is active or when it's just
+// waiting in a FileDesc queue.
+//
+ {
+ __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
+ switch (iMessage.Function())
+ {
+ case PMread:
+ iFile->ReadCancel();
+ break;
+ case PMrecvfrom:
+ iFile->RecvFromCancel();
+ break;
+ case PMwrite:
+ iFile->WriteCancel();
+ break;
+ case PMsendto:
+ iFile->SendToCancel();
+ break;
+ case PMfsync:
+ iFile->SyncCancel();
+ break;
+ case PMconnect:
+ iFile->ConnectCancel();
+ break;
+ case PMshutdown:
+ iFile->ShutdownCancel();
+ break;
+ case PMaccept:
+ iFile->AcceptCancel();
+ Fids().Attach(iNewFid,0); // cancel the reservation
+ break;
+ case PMioctl:
+ iFile->IoctlCancel();
+ break;
+ default:
+ // it would be wrong to get here, so leave well alone
+ break;
+ }
+ }
+
+CPosixRequest::~CPosixRequest()
+ {
+ Cancel();
+ if (iFile)
+ EndAsynch(KErrCancel);
+ }
+
+// Handling waiting on other processes
+//
+void CPosixRequest::EnList(CPosixRequest*& aHead)
+ {
+ iNext=aHead;
+ aHead=this;
+ }
+
+void CPosixRequest::WaitCompleted(TInt aPid, TInt aReason)
+ {
+ PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
+
+ __ASSERT_DEBUG(iMessage.Function()==PMwaitpid, CPosixServer::ServerPanic(EPosix_BadWaitCompletion));
+ params->pint[0]=aReason;
+ params->ret=aPid;
+ iMessage.Complete(KErrNone);
+
+ CPosixRequest* next=iNext;
+ iNext=0;
+ if (next)
+ next->WaitCompleted(aPid, aReason);
+ }
+
+static void ClosePipes(CPipeDesc* aPipes[3])
+ {
+ TInt i=0;
+ for (i=0; i<3; i++)
+ {
+ CPipeDesc* pipe=aPipes[i];
+ aPipes[i]=0;
+ if (pipe)
+ pipe->ClientClose();
+ }
+ }
+
+TInt CPosixIPCSession::AreYouMyMotherL(const RMessage2& aMessage)
+ {
+ TPosixIPCPid pid;
+ TPosixIPCReply reply;
+ aMessage.ReadL(0,pid);
+ DebugPrint(_L("Process %d asks am I its mother?"), pid());
+ CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
+ CPosixProcess* child=pServ->Child(pid());
+ if (!child)
+ return KErrNotFound; // you are no child of mine
+ DebugPrint(_L("Found child process"));
+ child->Sizes(reply);
+ aMessage.Write(1,reply);
+ return KErrNone;
+ }
+
+TInt CPosixIPCSession::HelloMumL(const RMessage2& aMessage)
+ {
+ TPosixIPCPid pid;
+ aMessage.ReadL(0,pid);
+
+ DebugPrint(_L("Process %d is requesting its inheritance"),pid());
+
+ CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
+ CPosixProcess* child=pServ->Child(pid());
+ if (!child)
+ return KErrNotFound; // you are no child of mine
+
+ // CopyToChildL will pull out the second and third element out directly so as
+ // to copy data to it. This is why data is passed in this way.
+ child->CopyToChildL(aMessage);
+ return KErrNone;
+ }
+
+void CPosixIPCSession::PipeRead(const RMessage2& aMessage)
+ {
+ TInt index=aMessage.Int0();
+ if (iPipes[index]==0)
+ aMessage.Complete(KErrEof); // go away, incorrect thing!
+ else
+ iPipes[index]->ClientRead(aMessage);
+ }
+
+void CPosixIPCSession::PipeWrite(const RMessage2& aMessage)
+ {
+ TInt index=aMessage.Int0();
+ if (iPipes[index]==0)
+ aMessage.Complete(KErrEof); // go away, incorrect thing!
+ else
+ iPipes[index]->ClientWrite(aMessage);
+ }
+
+void CPosixIPCSession::PipeIoctl(const RMessage2& aMessage)
+ {
+ TInt index=aMessage.Int0();
+ if (iPipes[index]==0)
+ aMessage.Complete(KErrEof); // go away, incorrect thing!
+ else
+ iPipes[index]->ClientIoctl(aMessage);
+ }
+
+void CPosixIPCSession::PipeClose(const RMessage2& aMessage)
+ {
+ TInt index=aMessage.Int0();
+ if (iPipes[index]!=0)
+ iPipes[index]->ClientClose();
+ aMessage.Complete(KErrNone);
+ }
+
+void CPosixIPCSession::PipeCancel(const RMessage2& aMessage)
+ {
+ TInt index=aMessage.Int0();
+ if (iPipes[index]!=0)
+ iPipes[index]->ClientCancel(aMessage);
+ aMessage.Complete(KErrNone);
+ }
+
+void CPosixIPCSession::ServiceL(const RMessage2& aMessage)
+//
+// Handle the communication between CPosixServers
+//
+ {
+ TInt response=KErrNone;
+ switch (aMessage.Function())
+ {
+ case PMAreYouMyMother:
+ response=AreYouMyMotherL(aMessage);
+ break;
+ case PMHelloMum:
+ response=HelloMumL(aMessage);
+ break;
+
+ case PMPipeRead:
+ PipeRead(aMessage);
+ return; // handles completion
+ case PMPipeWrite:
+ PipeWrite(aMessage);
+ return; // handles completion
+ case PMPipeIoctl:
+ PipeIoctl(aMessage);
+ return; // handles completion
+ case PMPipeClose:
+ PipeClose(aMessage);
+ return; // handles completion
+
+ case PMPipeCancel:
+ PipeCancel(aMessage);
+ return;
+
+ default:
+ response=KErrNotSupported;
+ break;
+ }
+ aMessage.Complete(response);
+ }
+
+void CPosixIPCSession::SetPipes(CPipeDesc* aPipes[3])
+//
+// Accept ownership of the pipes between child and parent
+//
+ {
+ TInt i=0;
+ for (i=0; i<3; i++)
+ {
+ CPipeDesc* pipe=aPipes[i];
+ iPipes[i]=pipe;
+ aPipes[i]=0;
+ if (pipe)
+ pipe->SetClientSide(iPipes[i]);
+ }
+ }
+
+CPosixIPCSession::~CPosixIPCSession()
+ {
+ ClosePipes(iPipes);
+ }
+
+// Active Object representing a POSIX process
+
+CPosixProcess::CPosixProcess(CPosixServer& aServer)
+ : CActive(EPriorityStandard), iServer(aServer)
+ {
+ // iPid=0;
+ // iWaiters=0;
+ // iNextProcess=0;
+ // iEnvironment=0;
+ // iWorkingDirectory=0;
+ }
+
+CPosixProcess* CPosixProcess::Find(CPosixProcess* proc, TInt pid)
+ {
+ while (proc!=0)
+ {
+ if (proc->iPid==pid)
+ return proc;
+ if (pid==-1 && !proc->IsAlive()) // for waitpid(WAIT_ANY,...)
+ return proc;
+ proc=proc->iNextProcess;
+ }
+ return 0;
+ }
+
+void CPosixProcess::Release(CPosixProcess** aHead, CPosixProcess* aChild)
+ {
+ while (*aHead!=0)
+ {
+ if ((*aHead)==aChild)
+ {
+ (*aHead)=aChild->iNextProcess;
+ aChild->iNextProcess=0;
+ delete aChild;
+ return;
+ }
+ aHead=&(*aHead)->iNextProcess;
+ }
+ }
+
+
+
+void CPosixProcess::POpen3L(PosixParams* aParams)
+ {
+ TInt i=0;
+ CPipeDesc* pipes[3];
+ for (i=0; i<3; i++)
+ {
+ if (aParams->pint[i]<0)
+ pipes[i]=0;
+ else
+ {
+ pipes[i]=new(ELeave) CPipeDesc(i);
+ pipes[i]->PushLC();
+ }
+ }
+ // truncate fileName to get the name of the executable
+ TPtrC16 fileName((TText16*)aParams->wptr[0]);
+ TPtrC16 commandLine((TText16*)aParams->cwptr[0]);
+
+ HBufC16* env=Env().ExternalizeLC(iVarCount,aParams->eptr[0]);
+ TFullName workingDirectory;
+ TInt err=Fs().SessionPath(workingDirectory);
+ User::LeaveIfError(err);
+ HBufC* cwd=workingDirectory.AllocLC();
+
+ // Use real processes
+ err=iChild.Create(fileName,commandLine,EOwnerThread);
+ User::LeaveIfError(err);
+ TProcessId id=iChild.Id();
+ iPid=*REINTERPRET_CAST(int*,&id);
+ iChild.Logon(iStatus);
+ CActiveScheduler::Add(this);
+ SetActive();
+ iChild.Resume();
+ iEnvironment=env;
+ iWorkingDirectory=cwd;
+ CleanupStack::Pop(2);
+ // Sort out the pipes
+ for (i=0; i<3; i++)
+ {
+ CPipeDesc* pipe=pipes[i];
+ iPipes[i]=pipe;
+ if (pipe!=0)
+ {
+ CleanupStack::Pop();
+ Fids().Attach(aParams->pint[i],pipe);
+ pipe->SetClientSide(iPipes[i]); // for FinalClose
+ }
+ }
+ }
+
+void CPosixProcess::Sizes(TPosixIPCReply& aReply) const
+ {
+ aReply().iWorkingDirectorySize=iWorkingDirectory->Length();
+ aReply().iEnvironmentSize=iEnvironment->Length();
+ aReply().iVarCount=iVarCount;
+ TUint mask=0;
+ TInt i=0;
+ for (i=0; i<3; i++)
+ {
+ if (iPipes[i]!=0)
+ mask |= 1<<i;
+ }
+ aReply().iPipeMask=mask;
+ }
+
+void CPosixProcess::CopyToChildL(const RMessage2& aMessage)
+ {
+ // copy iWorkingDirectory and iEnvironment to params
+ aMessage.WriteL(1, *iEnvironment);
+ aMessage.WriteL(2, *iWorkingDirectory);
+
+ // don't need this data anymore
+ delete iWorkingDirectory;
+ iWorkingDirectory=0;
+ delete iEnvironment;
+ iEnvironment=0;
+
+ (static_cast<CPosixIPCSession*>(aMessage.Session()))->SetPipes(iPipes);
+ }
+
+void CPosixProcess::RunL()
+//
+// Detects termination of the child process
+//
+ {
+ iExitReason=iStatus.Int();
+ iChild.Close();
+ DebugPrint(_L("Process %d appears to have terminated with status %d"), iPid, iExitReason);
+ ClosePipes(iPipes);
+
+ TInt reported=0;
+ CPosixRequest* waiters=iWaiters;
+ iWaiters=0;
+ if (waiters)
+ {
+ waiters->WaitCompleted(iPid,iExitReason);
+ reported=1;
+ }
+
+ // And any of the outstanding "wait for any" requests held in the server
+ waiters=iServer.Waiters();
+ if (waiters)
+ {
+ waiters->WaitCompleted(iPid,iExitReason);
+ reported=1;
+ }
+ if (reported)
+ iServer.Release(this);
+ }
+
+void CPosixProcess::DoCancel()
+ {
+ // panic if iNextProcess or iWaiters is non-zero?
+ iChild.LogonCancel(iStatus);
+ iChild.Close();
+ delete iEnvironment;
+ iEnvironment=0;
+ delete iWorkingDirectory;
+ iWorkingDirectory=0;
+ ClosePipes(iPipes);
+ }
+
+CPosixProcess::~CPosixProcess()
+ {
+ Cancel();
+ }
+
+// System Interface for process form of STDLIB
+
+CProcessSystemInterface::CProcessSystemInterface()
+ {}
+
+CProcessSystemInterface::~CProcessSystemInterface()
+ {
+ iSession.Close();
+ }
+
+MSystemInterface& CProcessSystemInterface::Clone()
+ {
+ return *(new CProcessSystemInterface);
+ }
+
+void CProcessSystemInterface::Release()
+ {
+ delete this;
+ }
+
+TInt CProcessSystemInterface::Connect()
+ {
+ return iSession.Connect(); // is this the right thread though?
+ }
+
+// CProcessSystemInterface functions
+//
+// These functions just package up their arguments for transmission to the
+// CPosixServer which will unpack them and call the corresponding function in
+// its associated CLocalSystemInterface, except for the asynchronous functions
+// (currently read/write/fsync) which the server handles separately using an active
+// object to defer the RMessage::Complete until the asynchronous operation has completed.
+
+static void doPanic(TInt aFunction, TInt aErr)
+ {
+ TBuf<100> detail;
+ _LIT(KProcessSystemInterfacePanic, "POSIXIF (%d)");
+ detail.Format(KProcessSystemInterfacePanic, aFunction);
+ User::Panic(detail,aErr);
+ }
+
+int CProcessSystemInterface::Request (TInt aFunction, int& anErrno)
+ {
+ TInt err=iSession.Request(aFunction,anErrno,iParams);
+ // KErrServerTerminated?
+ if (err!=KErrNone)
+ doPanic(aFunction,err); // moved out of line to reduce stack requirement
+ return iParams.ret;
+ }
+
+void CProcessSystemInterface::Request (TInt aFunction, int& anErrno, TRequestStatus& aStatus)
+ {
+ iSession.Request(aFunction,anErrno,iParams,aStatus);
+ }
+
+void CProcessSystemInterface::TerminateProcess (int status)
+ {
+ int anErrno;
+ iParams.fid=status;
+ Request(PMTerminateProcess,anErrno);
+ RProcess().Terminate(status); // just in case...
+ }
+
+int CProcessSystemInterface::dup (int fid, int& anErrno)
+ {
+ iParams.fid=fid;
+ return Request(PMdup,anErrno);
+ }
+
+int CProcessSystemInterface::dup2 (int fid, int fid2, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=fid2;
+ return Request(PMdup2,anErrno);
+ }
+
+int CProcessSystemInterface::open (const wchar_t* name, int mode, int perms, int& anErrno)
+ {
+ iParams.cwptr[0]=name;
+ iParams.pint[0]=mode;
+ iParams.pint[1]=perms;
+ return Request(PMopen,anErrno);
+ }
+
+int CProcessSystemInterface::read (int fid, char* buf, unsigned long len, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.ptr[0]=buf;
+ iParams.len[0]=len;
+ return Request(PMread,anErrno);
+ }
+
+int CProcessSystemInterface::write (int fid, const char* buf, unsigned long len, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.ptr[0]=CONST_CAST(char*,buf);
+ iParams.len[0]=len;
+ return Request(PMwrite,anErrno);
+ }
+
+int CProcessSystemInterface::fsync (int fid, int& anErrno)
+ {
+ iParams.fid=fid;
+ return Request(PMfsync,anErrno);
+ }
+
+int CProcessSystemInterface::close (int fid, int& anErrno)
+ {
+ iParams.fid=fid;
+ return Request(PMclose,anErrno);
+ }
+
+int CProcessSystemInterface::lseek (int fid, int offset, int whence, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=offset;
+ iParams.pint[1]=whence;
+ return Request(PMlseek,anErrno);
+ }
+
+int CProcessSystemInterface::fstat (int fid, struct stat *st, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.ptr[0]=(char*)st;
+ return Request(PMfstat,anErrno);
+ }
+
+
+wchar_t * CProcessSystemInterface::getcwd (wchar_t* buf, unsigned long len, int& anErrno)
+ {
+ iParams.wptr[0]=buf;
+
+ iParams.len[0]=len;
+ return (wchar_t *)Request(PMgetcwd,anErrno);
+ }
+
+
+int CProcessSystemInterface::chdir (const wchar_t* aPath, int& anErrno)
+ {
+ iParams.cwptr[0]=aPath;
+ return Request(PMchdir,anErrno);
+ }
+
+int CProcessSystemInterface::mkdir (const wchar_t* aPath, int perms, int& anErrno)
+ {
+ iParams.cwptr[0]=aPath;
+ iParams.pint[0]=perms;
+ return Request(PMmkdir,anErrno);
+ }
+
+int CProcessSystemInterface::rmdir (const wchar_t* aPath, int& anErrno)
+ {
+ iParams.cwptr[0]=aPath;
+ return Request(PMrmdir,anErrno);
+ }
+
+int CProcessSystemInterface::stat (const wchar_t* name, struct stat *st, int& anErrno)
+ {
+ iParams.cwptr[0]=name;
+ iParams.ptr[0]=(char*)st;
+ return Request(PMstat,anErrno);
+ }
+
+int CProcessSystemInterface::chmod (const wchar_t* name, int perms, int& anErrno)
+ {
+ iParams.cwptr[0]=name;
+ iParams.pint[0]=perms;
+ return Request(PMchmod,anErrno);
+ }
+
+int CProcessSystemInterface::unlink (const wchar_t* name, int& anErrno)
+ {
+ iParams.cwptr[0]=name;
+ return Request(PMunlink,anErrno);
+ }
+
+int CProcessSystemInterface::rename (const wchar_t* oldname, const wchar_t* newname, int& anErrno)
+ {
+ iParams.cwptr[0]=oldname;
+ iParams.cwptr[1]=newname;
+ return Request(PMrename,anErrno);
+ }
+
+TInt CProcessSystemInterface::ResolvePath (TParse& aResult, const wchar_t* path, TDes* aFilename)
+ {
+ TInt ignored;
+ iParams.ptr[0]=(char*)&aResult;
+ iParams.cwptr[0]=path;
+ iParams.ptr[1]=(char*)aFilename;
+ return Request(PMResolvePath,ignored);
+ }
+
+TInt CProcessSystemInterface::socket (int family, int style, int protocol, int& anErrno)
+ {
+ iParams.pint[0]=family;
+ iParams.pint[1]=style;
+ iParams.pint[2]=protocol;
+ return Request(PMsocket,anErrno);
+ }
+
+TInt CProcessSystemInterface::shutdown (int fid, int how, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=how;
+ return Request(PMshutdown,anErrno);
+ }
+
+TInt CProcessSystemInterface::listen (int fid, int n, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=n;
+ return Request(PMlisten,anErrno);
+ }
+
+TInt CProcessSystemInterface::accept (int fid, int& anErrno)
+ {
+ iParams.fid=fid;
+ return Request(PMaccept,anErrno);
+ }
+
+TInt CProcessSystemInterface::bind (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.addr.Set(addr, size);
+ return Request(PMbind,anErrno);
+ }
+
+TInt CProcessSystemInterface::connect (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.addr.Set(addr, size);
+ return Request(PMconnect,anErrno);
+ }
+
+TInt CProcessSystemInterface::recvfrom (int fid, char* buf, unsigned long len, int flags, struct sockaddr* from, unsigned long* fromsize, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.ptr[0]=buf;
+ iParams.len[0]=len;
+ iParams.pint[0]=flags;
+ iParams.addr.Prepare(from);
+ TInt nbytes=Request(PMrecvfrom,anErrno);
+ if (nbytes>=0) // i.e. no error
+ iParams.addr.Get(from,fromsize);
+ return nbytes;
+ }
+
+TInt CProcessSystemInterface::sendto (int fid, const char* buf, unsigned long len, int flags, struct sockaddr* to, unsigned long tosize, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.ptr[0]=CONST_CAST(char*,buf);
+ iParams.len[0]=len;
+ iParams.pint[0]=flags;
+ iParams.addr.Set(to,tosize);
+ return Request(PMsendto,anErrno);
+ }
+
+TInt CProcessSystemInterface::getsockopt (int fid, int level, int opt, void* buf, unsigned long* len, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=level;
+ iParams.pint[1]=opt;
+ iParams.ptr[0]=(char*)buf;
+ iParams.lenp[0]=len;
+ return Request(PMgetsockopt,anErrno);
+ }
+
+TInt CProcessSystemInterface::setsockopt (int fid, int level, int opt, void* buf, unsigned long len, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=level;
+ iParams.pint[1]=opt;
+ iParams.ptr[0]=(char*)buf;
+ iParams.len[0]=len;
+ return Request(PMsetsockopt,anErrno);
+ }
+
+TInt CProcessSystemInterface::sockname (int fid, struct sockaddr* addr, unsigned long* size, int anEnd, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.addr.Prepare(addr);
+ iParams.pint[0]=anEnd;
+ TInt err=Request(PMsockname,anErrno);
+ if (err==0)
+ iParams.addr.Get(addr,size);
+ return err;
+ }
+
+TInt CProcessSystemInterface::ioctl (int fid, int cmd, void* param, int& anErrno)
+ {
+ TRequestStatus ioctlStatus;
+ TInt err=ioctl(fid,cmd,param,ioctlStatus,anErrno);
+ if (err==KErrNone)
+ {
+ User::WaitForRequest(ioctlStatus);
+ err=ioctl_complete(fid,cmd,param,ioctlStatus,anErrno);
+ }
+ return err;
+ }
+
+wchar_t* CProcessSystemInterface::getenv (const wchar_t* name)
+ {
+ int dummy;
+ iParams.cwptr[0]=name;
+ return (wchar_t*)Request(PMgetenv,dummy);
+ }
+
+void CProcessSystemInterface::unsetenv (const wchar_t* name)
+ {
+ int dummy;
+ iParams.cwptr[0]=name;
+ Request(PMunsetenv,dummy);
+ }
+
+int CProcessSystemInterface::setenv (const wchar_t* name, const wchar_t* value, int rewrite, int& anErrno)
+ {
+ iParams.cwptr[0]=name;
+ iParams.cwptr[1]=value;
+ iParams.pint[0]=rewrite;
+ return Request(PMsetenv,anErrno);
+ }
+
+int CProcessSystemInterface::popen3 (const wchar_t* file, const wchar_t* cmd, const wchar_t* mode, wchar_t** env, int fids[3], int& anErrno)
+ {
+ iParams.wptr[0]=(wchar_t*)file;
+ iParams.cwptr[0]=cmd;
+ iParams.cwptr[1]=mode;
+ iParams.eptr[0]=env;
+ iParams.pint[0]=fids[0];
+ iParams.pint[1]=fids[1];
+ iParams.pint[2]=fids[2];
+ TInt child=Request(PMpopen3,anErrno);
+ if (child>=0)
+ {
+ fids[0]=iParams.pint[0];
+ fids[1]=iParams.pint[1];
+ fids[2]=iParams.pint[2];
+ };
+ return child;
+ }
+
+int CProcessSystemInterface::waitpid (int pid, int* status, int options, int& anErrno)
+ {
+ iParams.pint[0]=pid;
+ iParams.pint[1]=options;
+ TInt ret=Request(PMwaitpid,anErrno);
+ if (iParams.ret>=0 && status!=0)
+ {
+ *status=iParams.pint[0];
+ return iParams.ret;
+ }
+
+ return ret;
+ }
+
+// C++ version of asynchronous ioctl
+//
+// WARNING - this stuff is fairly insecure. We give no guarantees about whether the ioctl or
+// the completion will read the parameter information (sometimes it's both).
+//
+
+int CProcessSystemInterface::ioctl (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=cmd;
+ iParams.ptr[0]=(char*)param;
+
+ if (cmd & 0x4000)
+ Request(PMioctlN,anErrno,aStatus);
+ else
+ Request(PMioctl,anErrno,aStatus);
+
+ return KErrNone;
+ }
+
+int CProcessSystemInterface::ioctl_complete (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
+ {
+ iParams.fid=fid;
+ iParams.pint[0]=cmd;
+ iParams.ptr[0]=(char*)param;
+ iParams.ptr[1]=(char*)&aStatus;
+ return Request(PMioctlcomplete,anErrno);
+ }
+
+int CProcessSystemInterface::ioctl_cancel (int /*fid*/, int& /*anErrno*/)
+//
+// Actually a generic Cancel function for any outstanding operation
+//
+ {
+ TIpcArgs args;
+ return iSession.Request(PMcancel,args);
+ }