genericopenlibs/cstdlib/USTLIB/UPIPE.CPP
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implementation of pipes
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "POSIXIF.H"
       
    19 #include <sys/errno.h>
       
    20 #include <sys/stat.h>
       
    21 
       
    22 // Child end of the pipe
       
    23 
       
    24 CPipeChildDesc::CPipeChildDesc(TInt anIndex, RPosixSession& aSession)
       
    25 		: CFileDescBase(), iIndex(anIndex), iSession(aSession), iParamDes(0,0,0)
       
    26 	{}
       
    27 
       
    28 TInt CPipeChildDesc::LSeek (int&, int)
       
    29 	{
       
    30 	return ESPIPE;	// can't seek on a pipe
       
    31 	}
       
    32 
       
    33 TInt CPipeChildDesc::FStat(struct stat *st)
       
    34 	{
       
    35 	// I am a fifo about which little is known
       
    36 	st->st_mode = S_IFIFO;
       
    37 	st->st_blksize=0;
       
    38 	return KErrNone;
       
    39 	}
       
    40 
       
    41 void CPipeChildDesc::Read (TDes8& aBuf, TRequestStatus& aStatus)
       
    42 	{
       
    43 	if (iClientClosed || !IsReadable())
       
    44 		{
       
    45 		Complete(aStatus,KErrEof);
       
    46 		return;
       
    47 		}
       
    48 	TIpcArgs args(iIndex,&aBuf,aBuf.MaxLength());
       
    49 	iSession.Request(PMPipeRead,args,aStatus);	// asynchronous request
       
    50 	}
       
    51 
       
    52 void CPipeChildDesc::ReadCancel()
       
    53 	{
       
    54 	Cancel(PMPipeRead);
       
    55 	}
       
    56 
       
    57 TInt CPipeChildDesc::ReadCompletion(TDes8& aDesc, TInt aStatus)
       
    58 	{
       
    59 	if (aStatus==KErrEof)
       
    60 		{
       
    61 		ClientClose();
       
    62 		aDesc.Zero();		// set read length to zero
       
    63 		return KErrNone;	// indicates graceful close at the other end
       
    64 		}
       
    65 	return aStatus;
       
    66 	}
       
    67 
       
    68 void CPipeChildDesc::Write(TDes8& aDesc, TRequestStatus& aStatus)
       
    69 	{
       
    70 	if (iClientClosed || !IsWriteable())
       
    71 		{
       
    72 		Complete(aStatus,KErrEof);
       
    73 		return;
       
    74 		}
       
    75 	TIpcArgs args(iIndex,&aDesc,aDesc.Length());
       
    76 	iSession.Request(PMPipeWrite,args,aStatus);	// asynchronous request
       
    77 	}
       
    78 
       
    79 void CPipeChildDesc::WriteCancel()
       
    80 	{
       
    81 	Cancel(PMPipeWrite);
       
    82 	}
       
    83 
       
    84 TInt CPipeChildDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus)
       
    85 	{
       
    86 	if (aStatus==KErrEof)
       
    87 		ClientClose();
       
    88 	return aStatus;
       
    89 	}
       
    90 
       
    91 void CPipeChildDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
       
    92 //
       
    93 // The work of the Ioctl is done in the parent, including writing back to aParam?
       
    94 // Use the default completion which just returns aStatus.Int()
       
    95 //
       
    96 	{
       
    97 	if (iClientClosed)
       
    98 		{
       
    99 		Complete(aStatus,KErrEof);
       
   100 		return;
       
   101 		}
       
   102 	iParamDes.Set((TText8*)aParam,4,4);
       
   103 	TIpcArgs args(iIndex,aCmd,&iParamDes);	
       
   104 	if (aCmd==E32IOSELECT)
       
   105 		args.Set(3, *((TInt*)aParam));
       
   106 	iSession.Request(PMPipeIoctl,args,aStatus);	// asynchronous request
       
   107 	}
       
   108 
       
   109 void CPipeChildDesc::IoctlCancel()
       
   110 	{
       
   111 	Cancel(PMPipeIoctl);
       
   112 	}
       
   113 
       
   114 void CPipeChildDesc::Cancel(TInt aType)
       
   115 	{
       
   116 	if (iClientClosed)
       
   117 		return;
       
   118 	TIpcArgs args(iIndex,aType);
       
   119 	iSession.Request(PMPipeCancel,args);
       
   120 	}	
       
   121 
       
   122 TInt CPipeChildDesc::FinalClose()
       
   123 	{
       
   124 	ClientClose();
       
   125 	TIpcArgs args(iIndex);
       
   126 	return iSession.Request(PMPipeClose,args);		// synchronous request
       
   127 	}
       
   128 
       
   129 // 
       
   130 // Parent end of the pipe, where the real work is done
       
   131 //
       
   132 
       
   133 CPipeDesc::CPipeDesc(TInt anIndex) : CFileDescBase()
       
   134 	{
       
   135 	iIndex=anIndex;
       
   136 	}
       
   137 
       
   138 void CPipeDesc::SetClientSide(CPipeDesc*& aClientPointer)
       
   139 	{
       
   140 	iClientSide=&aClientPointer;
       
   141 	}
       
   142 
       
   143 _LIT(KCPipeDescPanic, "CPipeDesc");
       
   144 void CPipeDesc::Panic(TInt aReason)
       
   145 	{
       
   146 	User::Panic(KCPipeDescPanic,aReason);
       
   147 	}
       
   148 
       
   149 void CPipeDesc::Panic(RMessage2& aMessage, TInt aReason)
       
   150 	{
       
   151 	aMessage.Panic(KCPipeDescPanic,aReason);
       
   152 	}
       
   153 
       
   154 TInt CPipeDesc::LSeek (int&, int)
       
   155 	{
       
   156 	return ESPIPE;	// can't seek on a pipe
       
   157 	}
       
   158 
       
   159 TInt CPipeDesc::FStat(struct stat *st)
       
   160 	{
       
   161 	// I am a fifo about which little is known
       
   162 	st->st_mode = S_IFIFO;
       
   163 	st->st_blksize=0;
       
   164 	return KErrNone;
       
   165 	}
       
   166 
       
   167 void CPipeDesc::Read (TDes8& aBuf, TRequestStatus& aStatus)
       
   168 	{
       
   169 	if (!IsReadable())
       
   170 		{
       
   171 		Complete(aStatus, KErrEof);	// avoids treading on iStatus of pending Write
       
   172 		return;
       
   173 		}
       
   174 	__ASSERT_DEBUG(iStatus==0,Panic(1));
       
   175 	iStatus=&aStatus;
       
   176 	if (iClientClosed)
       
   177 		{
       
   178 		User::RequestComplete(iStatus,KErrEof);
       
   179 		return;
       
   180 		}
       
   181 	iReadBuf=&aBuf;
       
   182 	if (ClientIoctlPending())
       
   183 		CompleteClientIoctl();
       
   184 	if (iClientLength!=0)
       
   185 		TransferFromClient();
       
   186 	}
       
   187 
       
   188 void CPipeDesc::ReadCancel()
       
   189 	{
       
   190 	Cancel();
       
   191 	}
       
   192 
       
   193 TInt CPipeDesc::ReadCompletion(TDes8& aDesc, TInt aStatus)
       
   194 	{
       
   195 	if (aStatus==KErrEof)
       
   196 		{
       
   197 		ClientClose();
       
   198 		aDesc.Zero();		// set read length to zero
       
   199 		return KErrNone;	// indicates graceful close at the other end
       
   200 		}
       
   201 	return aStatus;
       
   202 	}
       
   203 
       
   204 void CPipeDesc::Write(TDes8& aDesc, TRequestStatus& aStatus)
       
   205 	{
       
   206 	if (!IsWriteable())
       
   207 		{
       
   208 		Complete(aStatus, KErrEof);	// avoids treading on iStatus of pending Read
       
   209 		return;
       
   210 		}
       
   211 	__ASSERT_DEBUG(iStatus==0,Panic(2));
       
   212 	iStatus=&aStatus;
       
   213 	if (iClientClosed)
       
   214 		{
       
   215 		User::RequestComplete(iStatus,KErrEof);
       
   216 		return;
       
   217 		}
       
   218 	iWriteBuf.Set(aDesc);
       
   219 	if (ClientIoctlPending())
       
   220 		CompleteClientIoctl();
       
   221 	if (iClientLength!=0)
       
   222 		TransferToClient();
       
   223 	}
       
   224 
       
   225 void CPipeDesc::WriteCancel()
       
   226 	{
       
   227 	Cancel();
       
   228 	}
       
   229 
       
   230 TInt CPipeDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus)
       
   231 	{
       
   232 	if (aStatus==KErrEof)
       
   233 		ClientClose();
       
   234 	return aStatus;
       
   235 	}
       
   236 
       
   237 void CPipeDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
       
   238 	{
       
   239 	TInt ret=KErrNone;
       
   240 	iIoctlStatus=&aStatus;
       
   241 	int *param=REINTERPRET_CAST(int*,aParam);
       
   242 	switch (aCmd)
       
   243 		{
       
   244 	case E32IONREAD:
       
   245 		// synchronous ioctls are handled in the completion routine.
       
   246 		break;
       
   247 	case E32IOSELECT:
       
   248 		{
       
   249 		int mask=(*param)&SelectMask();
       
   250 		if (mask!=0 && iClientLength==0)
       
   251 			return;	// wait for client to show up
       
   252 		}
       
   253 		break;
       
   254 	default:
       
   255 		ret=KErrNotSupported;
       
   256 		break;
       
   257 		}
       
   258 	User::RequestComplete(iIoctlStatus,ret);
       
   259 	}
       
   260 
       
   261 TInt CPipeDesc::IoctlCompletion(int aCmd, void* aParam, TInt aStatus)
       
   262 	{
       
   263 	TInt ret=aStatus;
       
   264 	if (ret!=KErrNone)
       
   265 		return ret;
       
   266 	int *param=REINTERPRET_CAST(int*,aParam);
       
   267 	switch (aCmd)
       
   268 		{
       
   269 	case E32IONREAD:
       
   270 		if (IsReadable())
       
   271 			*param=iClientLength;	// 0 if no outstanding client data
       
   272 		else
       
   273 			*param=0;	// claim that no data is available
       
   274 		break;
       
   275 	case E32IOSELECT:
       
   276 		{
       
   277 		int mask=0;
       
   278 		if (iClientLength!=0)
       
   279 			mask = SelectMask();
       
   280 		*param=(*param)&mask;
       
   281 		}
       
   282 		break;
       
   283 	default:
       
   284 		ret=KErrNotSupported;
       
   285 		break;
       
   286 		}
       
   287 	return ret;
       
   288 	}
       
   289 
       
   290 void CPipeDesc::IoctlCancel()
       
   291 	{
       
   292 	User::RequestComplete(iIoctlStatus,KErrCancel);
       
   293 	}
       
   294 
       
   295 void CPipeDesc::Cancel()
       
   296 	{
       
   297 	// Pipes are unidirectional, so don't need to distinguish between
       
   298 	// ReadCancel and WriteCancel
       
   299 	User::RequestComplete(iStatus,KErrCancel);
       
   300 	}
       
   301 
       
   302 // Client-side interface
       
   303 
       
   304 void CPipeDesc::ClientWrite(const RMessage2& aMessage)
       
   305 	{
       
   306 	__ASSERT_DEBUG(iClientLength==0,Panic(3));
       
   307 	if (iClientClosed)
       
   308 		{
       
   309 		aMessage.Complete(KErrEof);
       
   310 		return;
       
   311 		}
       
   312 	iClientLength=aMessage.Int2();
       
   313 	iClientOffset=0;
       
   314 	iMessage=aMessage;
       
   315 	if (iIoctlStatus!=0)
       
   316 		User::RequestComplete(iIoctlStatus,KErrNone);
       
   317 	if (iStatus!=0)
       
   318 		TransferFromClient();
       
   319 	}
       
   320 
       
   321 void CPipeDesc::ClientRead(const RMessage2& aMessage)
       
   322 	{
       
   323 	__ASSERT_DEBUG(iClientLength==0,Panic(4));
       
   324 	if (iClientClosed)
       
   325 		{
       
   326 		aMessage.Complete(KErrEof);
       
   327 		return;
       
   328 		}
       
   329 	iClientLength=aMessage.Int2();
       
   330 	iMessage=aMessage;
       
   331 	if (iIoctlStatus!=0)
       
   332 		User::RequestComplete(iIoctlStatus,KErrNone);
       
   333 	if (iStatus!=0)
       
   334 		TransferToClient();
       
   335 	}
       
   336 
       
   337 void CPipeDesc::ClientIoctl(const RMessage2& aMessage)
       
   338 	{
       
   339 	__ASSERT_DEBUG(!ClientIoctlPending(),Panic(7));
       
   340 	if (iClientClosed)
       
   341 		{
       
   342 		aMessage.Complete(KErrEof);
       
   343 		return;
       
   344 		}
       
   345 	iClientIoctlPending=1;
       
   346 	iIoctlMessage=aMessage;
       
   347 	TInt ret=KErrNone;
       
   348 	switch (aMessage.Int1())
       
   349 		{
       
   350 	case E32IONREAD:
       
   351 		// synchronous ioctls are handled in the completion routine.
       
   352 		break;
       
   353 	case E32IOSELECT:
       
   354 		{
       
   355 		int mask=aMessage.Int3();
       
   356 		mask&=ClientSelectMask();
       
   357 		if (mask!=0 && iStatus==0)
       
   358 			return;	// wait for parent activity
       
   359 		}
       
   360 		break;
       
   361 	default:
       
   362 		ret=KErrNotSupported;
       
   363 		break;
       
   364 		}
       
   365 	CompleteClientIoctl(ret);
       
   366 	}
       
   367 
       
   368 void CPipeDesc::ClientCancel(const RMessage2& aMessage)
       
   369 	{
       
   370 	if (aMessage.Int1()==PMPipeIoctl)
       
   371 		{
       
   372 		if (ClientIoctlPending())
       
   373 			CompleteClientIoctl(KErrCancel);
       
   374 		return;
       
   375 		}
       
   376 	// Pipes are unidirectional, so Read and Write are cancelled by
       
   377 	// cancelling the current client operation.
       
   378 	//
       
   379 	if (iClientLength!=0)
       
   380 		{
       
   381 		iMessage.Complete(KErrCancel);
       
   382 		iClientLength=0;
       
   383 		}
       
   384 	}
       
   385 
       
   386 void CPipeDesc::ClientClose()
       
   387 	{
       
   388 	iClientClosed=1;
       
   389 	// terminate any pending requests
       
   390 	if (iStatus!=0)
       
   391 		User::RequestComplete(iStatus,KErrEof);
       
   392 	if (ClientIoctlPending())
       
   393 		CompleteClientIoctl(KErrEof);
       
   394 	if (iClientLength!=0)
       
   395 		{
       
   396 		iMessage.Complete(KErrEof);
       
   397 		iClientLength=0;
       
   398 		}
       
   399 	}
       
   400 
       
   401 TInt CPipeDesc::FinalClose()
       
   402 	{
       
   403 	ClientClose();
       
   404 	if (iClientSide)
       
   405 		{
       
   406 		*iClientSide=0;
       
   407 		iClientSide=0;
       
   408 		}
       
   409 	return KErrNone;
       
   410 	}
       
   411 
       
   412 void CPipeDesc::TransferFromClient()
       
   413 //
       
   414 // Handle transfer of data from client to parent.
       
   415 // Always complete the parent read, but only complete the child write when
       
   416 // all of the data has been consumed.
       
   417 //
       
   418 	{
       
   419 	TRAPD(err,iMessage.ReadL(1,*iReadBuf,iClientOffset));
       
   420 	if (err)
       
   421 		{
       
   422 		Panic(iMessage,5);
       
   423 		iClientLength=0;
       
   424 		ClientClose();	// will complete the parent read
       
   425 		return;
       
   426 		}
       
   427 	TInt length=iReadBuf->Length();	// record the amount of data transferred
       
   428 	User::RequestComplete(iStatus,KErrNone);
       
   429 	iClientOffset+=length;
       
   430 	iClientLength-=length;
       
   431 	if (iClientLength==0)
       
   432 		iMessage.Complete(KErrNone);
       
   433 	}
       
   434 
       
   435 void CPipeDesc::TransferToClient()
       
   436 //
       
   437 // Handle transfer from parent to client
       
   438 // Always complete the client read, but only complete the parent write when
       
   439 // all of the data has been consumed.
       
   440 //
       
   441 	{
       
   442 	TInt err=KErrNone;
       
   443 	TInt length=iWriteBuf.Length();
       
   444 	TInt written=length;
       
   445 	if (iClientLength >= length)
       
   446 		{
       
   447 		TRAP(err,iMessage.WriteL(1,iWriteBuf,0));
       
   448 		}
       
   449 	else
       
   450 		{
       
   451 		written=iClientLength;
       
   452 		TRAP(err,iMessage.WriteL(1,iWriteBuf.Left(written),0));
       
   453 		}
       
   454 	iClientLength=0;
       
   455 	if (err)
       
   456 		{
       
   457 		Panic(iMessage,6);
       
   458 		ClientClose();	// will complete the parent write
       
   459 		return;
       
   460 		}
       
   461 	iMessage.Complete(KErrNone);
       
   462 	length-=written;
       
   463 	if (length==0)
       
   464 		User::RequestComplete(iStatus,KErrNone);
       
   465 	else
       
   466 		iWriteBuf.Set(iWriteBuf.Right(length));
       
   467 	}
       
   468 
       
   469 void CPipeDesc::CompleteClientIoctl(TInt ret)
       
   470 	{
       
   471 	if (ret!=KErrNone)
       
   472 		{
       
   473 		iIoctlMessage.Complete(ret);
       
   474 		iClientIoctlPending=0;
       
   475 		return;
       
   476 		}
       
   477 	CompleteClientIoctl();
       
   478 	}
       
   479 
       
   480 void CPipeDesc::CompleteClientIoctl()
       
   481 //
       
   482 // Complete outstanding PMPipeIoctl message
       
   483 //
       
   484 	{
       
   485 	TInt ret=KErrNone;
       
   486 	int param=0;
       
   487 	switch (iIoctlMessage.Int1())
       
   488 		{
       
   489 	case E32IONREAD:
       
   490 		if (IsWriteable() && iStatus!=0)
       
   491 			param=iWriteBuf.Length();
       
   492 		else
       
   493 			param=0;	// claim that no data is available
       
   494 		break;
       
   495 	case E32IOSELECT:
       
   496 		{
       
   497 		int mask=0;
       
   498 		if (iStatus!=0)
       
   499 			mask=ClientSelectMask();
       
   500 		param=(iIoctlMessage.Int3())&mask;
       
   501 		}
       
   502 		break;
       
   503 	default:
       
   504 		ret=KErrNotSupported;
       
   505 		break;
       
   506 		}
       
   507 	if (ret==KErrNone)
       
   508 		{
       
   509 		TPtrC8 paramReturn((const TText8*)&param,4);
       
   510 		TRAP(ret,iIoctlMessage.WriteL(2,paramReturn,0));
       
   511 		}
       
   512 	iIoctlMessage.Complete(ret);
       
   513 	iClientIoctlPending=0;
       
   514 	}