sl@0: // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Implementation of pipes sl@0: // sl@0: // sl@0: sl@0: #include "POSIXIF.H" sl@0: #include sl@0: #include sl@0: sl@0: // Child end of the pipe sl@0: sl@0: CPipeChildDesc::CPipeChildDesc(TInt anIndex, RPosixSession& aSession) sl@0: : CFileDescBase(), iIndex(anIndex), iSession(aSession), iParamDes(0,0,0) sl@0: {} sl@0: sl@0: TInt CPipeChildDesc::LSeek (int&, int) sl@0: { sl@0: return ESPIPE; // can't seek on a pipe sl@0: } sl@0: sl@0: TInt CPipeChildDesc::FStat(struct stat *st) sl@0: { sl@0: // I am a fifo about which little is known sl@0: st->st_mode = S_IFIFO; sl@0: st->st_blksize=0; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CPipeChildDesc::Read (TDes8& aBuf, TRequestStatus& aStatus) sl@0: { sl@0: if (iClientClosed || !IsReadable()) sl@0: { sl@0: Complete(aStatus,KErrEof); sl@0: return; sl@0: } sl@0: TIpcArgs args(iIndex,&aBuf,aBuf.MaxLength()); sl@0: iSession.Request(PMPipeRead,args,aStatus); // asynchronous request sl@0: } sl@0: sl@0: void CPipeChildDesc::ReadCancel() sl@0: { sl@0: Cancel(PMPipeRead); sl@0: } sl@0: sl@0: TInt CPipeChildDesc::ReadCompletion(TDes8& aDesc, TInt aStatus) sl@0: { sl@0: if (aStatus==KErrEof) sl@0: { sl@0: ClientClose(); sl@0: aDesc.Zero(); // set read length to zero sl@0: return KErrNone; // indicates graceful close at the other end sl@0: } sl@0: return aStatus; sl@0: } sl@0: sl@0: void CPipeChildDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) sl@0: { sl@0: if (iClientClosed || !IsWriteable()) sl@0: { sl@0: Complete(aStatus,KErrEof); sl@0: return; sl@0: } sl@0: TIpcArgs args(iIndex,&aDesc,aDesc.Length()); sl@0: iSession.Request(PMPipeWrite,args,aStatus); // asynchronous request sl@0: } sl@0: sl@0: void CPipeChildDesc::WriteCancel() sl@0: { sl@0: Cancel(PMPipeWrite); sl@0: } sl@0: sl@0: TInt CPipeChildDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus) sl@0: { sl@0: if (aStatus==KErrEof) sl@0: ClientClose(); sl@0: return aStatus; sl@0: } sl@0: sl@0: void CPipeChildDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus) sl@0: // sl@0: // The work of the Ioctl is done in the parent, including writing back to aParam? sl@0: // Use the default completion which just returns aStatus.Int() sl@0: // sl@0: { sl@0: if (iClientClosed) sl@0: { sl@0: Complete(aStatus,KErrEof); sl@0: return; sl@0: } sl@0: iParamDes.Set((TText8*)aParam,4,4); sl@0: TIpcArgs args(iIndex,aCmd,&iParamDes); sl@0: if (aCmd==E32IOSELECT) sl@0: args.Set(3, *((TInt*)aParam)); sl@0: iSession.Request(PMPipeIoctl,args,aStatus); // asynchronous request sl@0: } sl@0: sl@0: void CPipeChildDesc::IoctlCancel() sl@0: { sl@0: Cancel(PMPipeIoctl); sl@0: } sl@0: sl@0: void CPipeChildDesc::Cancel(TInt aType) sl@0: { sl@0: if (iClientClosed) sl@0: return; sl@0: TIpcArgs args(iIndex,aType); sl@0: iSession.Request(PMPipeCancel,args); sl@0: } sl@0: sl@0: TInt CPipeChildDesc::FinalClose() sl@0: { sl@0: ClientClose(); sl@0: TIpcArgs args(iIndex); sl@0: return iSession.Request(PMPipeClose,args); // synchronous request sl@0: } sl@0: sl@0: // sl@0: // Parent end of the pipe, where the real work is done sl@0: // sl@0: sl@0: CPipeDesc::CPipeDesc(TInt anIndex) : CFileDescBase() sl@0: { sl@0: iIndex=anIndex; sl@0: } sl@0: sl@0: void CPipeDesc::SetClientSide(CPipeDesc*& aClientPointer) sl@0: { sl@0: iClientSide=&aClientPointer; sl@0: } sl@0: sl@0: _LIT(KCPipeDescPanic, "CPipeDesc"); sl@0: void CPipeDesc::Panic(TInt aReason) sl@0: { sl@0: User::Panic(KCPipeDescPanic,aReason); sl@0: } sl@0: sl@0: void CPipeDesc::Panic(RMessage2& aMessage, TInt aReason) sl@0: { sl@0: aMessage.Panic(KCPipeDescPanic,aReason); sl@0: } sl@0: sl@0: TInt CPipeDesc::LSeek (int&, int) sl@0: { sl@0: return ESPIPE; // can't seek on a pipe sl@0: } sl@0: sl@0: TInt CPipeDesc::FStat(struct stat *st) sl@0: { sl@0: // I am a fifo about which little is known sl@0: st->st_mode = S_IFIFO; sl@0: st->st_blksize=0; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CPipeDesc::Read (TDes8& aBuf, TRequestStatus& aStatus) sl@0: { sl@0: if (!IsReadable()) sl@0: { sl@0: Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Write sl@0: return; sl@0: } sl@0: __ASSERT_DEBUG(iStatus==0,Panic(1)); sl@0: iStatus=&aStatus; sl@0: if (iClientClosed) sl@0: { sl@0: User::RequestComplete(iStatus,KErrEof); sl@0: return; sl@0: } sl@0: iReadBuf=&aBuf; sl@0: if (ClientIoctlPending()) sl@0: CompleteClientIoctl(); sl@0: if (iClientLength!=0) sl@0: TransferFromClient(); sl@0: } sl@0: sl@0: void CPipeDesc::ReadCancel() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: TInt CPipeDesc::ReadCompletion(TDes8& aDesc, TInt aStatus) sl@0: { sl@0: if (aStatus==KErrEof) sl@0: { sl@0: ClientClose(); sl@0: aDesc.Zero(); // set read length to zero sl@0: return KErrNone; // indicates graceful close at the other end sl@0: } sl@0: return aStatus; sl@0: } sl@0: sl@0: void CPipeDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) sl@0: { sl@0: if (!IsWriteable()) sl@0: { sl@0: Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Read sl@0: return; sl@0: } sl@0: __ASSERT_DEBUG(iStatus==0,Panic(2)); sl@0: iStatus=&aStatus; sl@0: if (iClientClosed) sl@0: { sl@0: User::RequestComplete(iStatus,KErrEof); sl@0: return; sl@0: } sl@0: iWriteBuf.Set(aDesc); sl@0: if (ClientIoctlPending()) sl@0: CompleteClientIoctl(); sl@0: if (iClientLength!=0) sl@0: TransferToClient(); sl@0: } sl@0: sl@0: void CPipeDesc::WriteCancel() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: TInt CPipeDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus) sl@0: { sl@0: if (aStatus==KErrEof) sl@0: ClientClose(); sl@0: return aStatus; sl@0: } sl@0: sl@0: void CPipeDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus) sl@0: { sl@0: TInt ret=KErrNone; sl@0: iIoctlStatus=&aStatus; sl@0: int *param=REINTERPRET_CAST(int*,aParam); sl@0: switch (aCmd) sl@0: { sl@0: case E32IONREAD: sl@0: // synchronous ioctls are handled in the completion routine. sl@0: break; sl@0: case E32IOSELECT: sl@0: { sl@0: int mask=(*param)&SelectMask(); sl@0: if (mask!=0 && iClientLength==0) sl@0: return; // wait for client to show up sl@0: } sl@0: break; sl@0: default: sl@0: ret=KErrNotSupported; sl@0: break; sl@0: } sl@0: User::RequestComplete(iIoctlStatus,ret); sl@0: } sl@0: sl@0: TInt CPipeDesc::IoctlCompletion(int aCmd, void* aParam, TInt aStatus) sl@0: { sl@0: TInt ret=aStatus; sl@0: if (ret!=KErrNone) sl@0: return ret; sl@0: int *param=REINTERPRET_CAST(int*,aParam); sl@0: switch (aCmd) sl@0: { sl@0: case E32IONREAD: sl@0: if (IsReadable()) sl@0: *param=iClientLength; // 0 if no outstanding client data sl@0: else sl@0: *param=0; // claim that no data is available sl@0: break; sl@0: case E32IOSELECT: sl@0: { sl@0: int mask=0; sl@0: if (iClientLength!=0) sl@0: mask = SelectMask(); sl@0: *param=(*param)&mask; sl@0: } sl@0: break; sl@0: default: sl@0: ret=KErrNotSupported; sl@0: break; sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: void CPipeDesc::IoctlCancel() sl@0: { sl@0: User::RequestComplete(iIoctlStatus,KErrCancel); sl@0: } sl@0: sl@0: void CPipeDesc::Cancel() sl@0: { sl@0: // Pipes are unidirectional, so don't need to distinguish between sl@0: // ReadCancel and WriteCancel sl@0: User::RequestComplete(iStatus,KErrCancel); sl@0: } sl@0: sl@0: // Client-side interface sl@0: sl@0: void CPipeDesc::ClientWrite(const RMessage2& aMessage) sl@0: { sl@0: __ASSERT_DEBUG(iClientLength==0,Panic(3)); sl@0: if (iClientClosed) sl@0: { sl@0: aMessage.Complete(KErrEof); sl@0: return; sl@0: } sl@0: iClientLength=aMessage.Int2(); sl@0: iClientOffset=0; sl@0: iMessage=aMessage; sl@0: if (iIoctlStatus!=0) sl@0: User::RequestComplete(iIoctlStatus,KErrNone); sl@0: if (iStatus!=0) sl@0: TransferFromClient(); sl@0: } sl@0: sl@0: void CPipeDesc::ClientRead(const RMessage2& aMessage) sl@0: { sl@0: __ASSERT_DEBUG(iClientLength==0,Panic(4)); sl@0: if (iClientClosed) sl@0: { sl@0: aMessage.Complete(KErrEof); sl@0: return; sl@0: } sl@0: iClientLength=aMessage.Int2(); sl@0: iMessage=aMessage; sl@0: if (iIoctlStatus!=0) sl@0: User::RequestComplete(iIoctlStatus,KErrNone); sl@0: if (iStatus!=0) sl@0: TransferToClient(); sl@0: } sl@0: sl@0: void CPipeDesc::ClientIoctl(const RMessage2& aMessage) sl@0: { sl@0: __ASSERT_DEBUG(!ClientIoctlPending(),Panic(7)); sl@0: if (iClientClosed) sl@0: { sl@0: aMessage.Complete(KErrEof); sl@0: return; sl@0: } sl@0: iClientIoctlPending=1; sl@0: iIoctlMessage=aMessage; sl@0: TInt ret=KErrNone; sl@0: switch (aMessage.Int1()) sl@0: { sl@0: case E32IONREAD: sl@0: // synchronous ioctls are handled in the completion routine. sl@0: break; sl@0: case E32IOSELECT: sl@0: { sl@0: int mask=aMessage.Int3(); sl@0: mask&=ClientSelectMask(); sl@0: if (mask!=0 && iStatus==0) sl@0: return; // wait for parent activity sl@0: } sl@0: break; sl@0: default: sl@0: ret=KErrNotSupported; sl@0: break; sl@0: } sl@0: CompleteClientIoctl(ret); sl@0: } sl@0: sl@0: void CPipeDesc::ClientCancel(const RMessage2& aMessage) sl@0: { sl@0: if (aMessage.Int1()==PMPipeIoctl) sl@0: { sl@0: if (ClientIoctlPending()) sl@0: CompleteClientIoctl(KErrCancel); sl@0: return; sl@0: } sl@0: // Pipes are unidirectional, so Read and Write are cancelled by sl@0: // cancelling the current client operation. sl@0: // sl@0: if (iClientLength!=0) sl@0: { sl@0: iMessage.Complete(KErrCancel); sl@0: iClientLength=0; sl@0: } sl@0: } sl@0: sl@0: void CPipeDesc::ClientClose() sl@0: { sl@0: iClientClosed=1; sl@0: // terminate any pending requests sl@0: if (iStatus!=0) sl@0: User::RequestComplete(iStatus,KErrEof); sl@0: if (ClientIoctlPending()) sl@0: CompleteClientIoctl(KErrEof); sl@0: if (iClientLength!=0) sl@0: { sl@0: iMessage.Complete(KErrEof); sl@0: iClientLength=0; sl@0: } sl@0: } sl@0: sl@0: TInt CPipeDesc::FinalClose() sl@0: { sl@0: ClientClose(); sl@0: if (iClientSide) sl@0: { sl@0: *iClientSide=0; sl@0: iClientSide=0; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CPipeDesc::TransferFromClient() sl@0: // sl@0: // Handle transfer of data from client to parent. sl@0: // Always complete the parent read, but only complete the child write when sl@0: // all of the data has been consumed. sl@0: // sl@0: { sl@0: TRAPD(err,iMessage.ReadL(1,*iReadBuf,iClientOffset)); sl@0: if (err) sl@0: { sl@0: Panic(iMessage,5); sl@0: iClientLength=0; sl@0: ClientClose(); // will complete the parent read sl@0: return; sl@0: } sl@0: TInt length=iReadBuf->Length(); // record the amount of data transferred sl@0: User::RequestComplete(iStatus,KErrNone); sl@0: iClientOffset+=length; sl@0: iClientLength-=length; sl@0: if (iClientLength==0) sl@0: iMessage.Complete(KErrNone); sl@0: } sl@0: sl@0: void CPipeDesc::TransferToClient() sl@0: // sl@0: // Handle transfer from parent to client sl@0: // Always complete the client read, but only complete the parent write when sl@0: // all of the data has been consumed. sl@0: // sl@0: { sl@0: TInt err=KErrNone; sl@0: TInt length=iWriteBuf.Length(); sl@0: TInt written=length; sl@0: if (iClientLength >= length) sl@0: { sl@0: TRAP(err,iMessage.WriteL(1,iWriteBuf,0)); sl@0: } sl@0: else sl@0: { sl@0: written=iClientLength; sl@0: TRAP(err,iMessage.WriteL(1,iWriteBuf.Left(written),0)); sl@0: } sl@0: iClientLength=0; sl@0: if (err) sl@0: { sl@0: Panic(iMessage,6); sl@0: ClientClose(); // will complete the parent write sl@0: return; sl@0: } sl@0: iMessage.Complete(KErrNone); sl@0: length-=written; sl@0: if (length==0) sl@0: User::RequestComplete(iStatus,KErrNone); sl@0: else sl@0: iWriteBuf.Set(iWriteBuf.Right(length)); sl@0: } sl@0: sl@0: void CPipeDesc::CompleteClientIoctl(TInt ret) sl@0: { sl@0: if (ret!=KErrNone) sl@0: { sl@0: iIoctlMessage.Complete(ret); sl@0: iClientIoctlPending=0; sl@0: return; sl@0: } sl@0: CompleteClientIoctl(); sl@0: } sl@0: sl@0: void CPipeDesc::CompleteClientIoctl() sl@0: // sl@0: // Complete outstanding PMPipeIoctl message sl@0: // sl@0: { sl@0: TInt ret=KErrNone; sl@0: int param=0; sl@0: switch (iIoctlMessage.Int1()) sl@0: { sl@0: case E32IONREAD: sl@0: if (IsWriteable() && iStatus!=0) sl@0: param=iWriteBuf.Length(); sl@0: else sl@0: param=0; // claim that no data is available sl@0: break; sl@0: case E32IOSELECT: sl@0: { sl@0: int mask=0; sl@0: if (iStatus!=0) sl@0: mask=ClientSelectMask(); sl@0: param=(iIoctlMessage.Int3())&mask; sl@0: } sl@0: break; sl@0: default: sl@0: ret=KErrNotSupported; sl@0: break; sl@0: } sl@0: if (ret==KErrNone) sl@0: { sl@0: TPtrC8 paramReturn((const TText8*)¶m,4); sl@0: TRAP(ret,iIoctlMessage.WriteL(2,paramReturn,0)); sl@0: } sl@0: iIoctlMessage.Complete(ret); sl@0: iClientIoctlPending=0; sl@0: }