|
1 // Copyright (c) 2006-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 the License "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 // |
|
15 |
|
16 /** |
|
17 @file rpipe.cpp |
|
18 @internalTechnology |
|
19 */ |
|
20 |
|
21 #include <e32def.h> |
|
22 #include <e32def_private.h> |
|
23 #include "rpipe.h" |
|
24 |
|
25 EXPORT_C TInt RPipe::Init() |
|
26 /** |
|
27 Static method to load the pipe device driver. |
|
28 |
|
29 @param None |
|
30 |
|
31 @return KErrNone If the pipe is successfully loaded, otherwise one of the |
|
32 system wide error code. |
|
33 */ |
|
34 { |
|
35 _LIT(KDriverLddFileName,"PIPELIB"); |
|
36 return User::LoadLogicalDevice(KDriverLddFileName); |
|
37 } |
|
38 |
|
39 |
|
40 EXPORT_C TInt RPipe::Create( TInt aSize, RPipe& aReader, RPipe& aWriter, TOwnerType aTypeR, TOwnerType aTypeW) |
|
41 /** |
|
42 Static method to create a new, unnamed pipe. |
|
43 By default, any thread in the process can use the handle to access the Pipe. However, |
|
44 specifying EOwnerThread as the second and fourth parameter to this function, means |
|
45 that only the creating thread can use this handle to access the Pipe. |
|
46 |
|
47 @param aReader Handle to the read end of the pipe. If the call is successful, |
|
48 this handle will be opened for reading. |
|
49 @param aWriter Handle to the write end of the pipe. If the call is successful, |
|
50 this handle will be opened for writing. |
|
51 @param aTypeR, aTypeW The type of the ownership of the handle to be created for the |
|
52 read and write |
|
53 @param aSize Size of the pipe to be created, in bytes. |
|
54 |
|
55 @return KErrNone Pipe successfully created and the read and write handles opened, |
|
56 KErrOverflow Maximum number of pipes has been reached. |
|
57 KErrNoMemory Insufficient memory to create pipe |
|
58 KErrArgument If the specified size is negative or zero |
|
59 KErrInUse The current handle has already been opened. |
|
60 otherwise one of the other system wide error codes |
|
61 */ |
|
62 |
|
63 { |
|
64 TInt err = aReader.Create(aSize, aTypeR); |
|
65 if (err != KErrNone ) |
|
66 return err; |
|
67 else |
|
68 { |
|
69 err = aWriter.Open(aReader, aTypeW); |
|
70 if(err!= KErrNone) |
|
71 aReader.Close(); |
|
72 } |
|
73 return err; |
|
74 } |
|
75 |
|
76 TInt RPipe::Create(TInt aSize, TOwnerType aType) |
|
77 /** |
|
78 Creates a Kernel side pipe and opens a handle for reading. |
|
79 By default any thread in the process can use the handle to access to Read the Pipe. |
|
80 However, specifying EOwnerThread as the second parameter to this function, means |
|
81 that only the creating thread can use this handle to access the pipe. |
|
82 |
|
83 @param aSize Size of the pipe to create, in bytes. |
|
84 |
|
85 @param aType The type of the handle to be created for the reading |
|
86 end of the pipe |
|
87 |
|
88 @return KErrNone Pipe successfully created and handle opened for reading, |
|
89 KErrInUse The current handle has already been opened. |
|
90 KErrOverflow Maximum number of pipes has been reached. |
|
91 KErrNoMemory Insufficient memory to create pipe |
|
92 KErrArgument If the specified size is negative or zero |
|
93 otherwise one of the other system wide error code |
|
94 */ |
|
95 { |
|
96 |
|
97 // Check if the current handle is already opened for reading/writing |
|
98 if ( iHandle && HandleType()) |
|
99 return KErrInUse; |
|
100 |
|
101 if(aSize <= 0 ) |
|
102 return KErrArgument; |
|
103 |
|
104 // Perform the capability check and create the channel |
|
105 TInt err = DoCreate(Name(), VersionRequired(), KNullUnit, NULL, NULL, aType, ETrue); |
|
106 if (err!= KErrNone) |
|
107 return err; |
|
108 |
|
109 // Create an un-named pipe with the specified size |
|
110 err = DoControl(ECreateUnNamedPipe, (TAny*)&aSize); |
|
111 if (err>0) |
|
112 { |
|
113 iSize = DoControl(ESize); |
|
114 iHandleType = EReadChannel; |
|
115 iPipeHandle = err; |
|
116 err = KErrNone; |
|
117 } |
|
118 else |
|
119 { |
|
120 Close(); |
|
121 } |
|
122 return err; |
|
123 } |
|
124 |
|
125 |
|
126 EXPORT_C TInt RPipe::Open(RMessagePtr2 aMessage, TInt aParam, TOwnerType aType) |
|
127 /** |
|
128 Opens a handle to pipe using a handle number sent by a client to a server. |
|
129 This function is called by the server. |
|
130 |
|
131 @param aMessage The message pointer. |
|
132 |
|
133 @param aParam An index specifying which of the four message arguments contains the handle number. |
|
134 |
|
135 @param aType An enumeration whose enumerators define the ownership of this logical channel handle. |
|
136 If not explicitly specified, EOwnerProcess is taken as default. |
|
137 @return KErrNone if successful; |
|
138 KErrArgument if the value of aParam is outside the range 0-3; |
|
139 KErrBadHandle if not a valid handle; |
|
140 otherwise one of the other system-wide error codes. |
|
141 |
|
142 |
|
143 */ |
|
144 { |
|
145 TInt err = RBusLogicalChannel::Open(aMessage, aParam, aType); |
|
146 if (err) |
|
147 { |
|
148 return err; |
|
149 } |
|
150 err = DoControl(RPipe::EGetPipeInfo,&iHandleType,&iSize); |
|
151 return err; |
|
152 |
|
153 } |
|
154 |
|
155 |
|
156 EXPORT_C TInt RPipe::Open(TInt aArgumentIndex, TOwnerType aType) |
|
157 /** |
|
158 Opens the handle to pipe which is passed by a process to child process using |
|
159 RProcess.SetParameter function call. Pipe handle type remains same(i.e. if read handle is passed |
|
160 by process then read handle will be open). |
|
161 |
|
162 @param aArgumentIndex An index that identifies the slot in the process environment |
|
163 data that contains the handle number. This is a value relative |
|
164 to zero, i.e. 0 is the first item/slot. This can range from 0 to 15. |
|
165 |
|
166 @param aType The type of the handle to be created for the read/write end |
|
167 |
|
168 @return KErrNone Pipe successfully created, |
|
169 otherwise of the other system wide error code. |
|
170 */ |
|
171 { |
|
172 |
|
173 TInt err = RBusLogicalChannel::Open(aArgumentIndex,aType); |
|
174 if (err) |
|
175 { |
|
176 return err; |
|
177 } |
|
178 err = DoControl(RPipe::EGetPipeInfo,&iHandleType,&iSize); |
|
179 return err; |
|
180 } |
|
181 |
|
182 TInt RPipe::Open(const RPipe& aReader, TOwnerType aType) |
|
183 /** |
|
184 Opens a handle to write to a pipe. The pipe must have been created previously. |
|
185 By default any thread in the process can use the handle to access to write to |
|
186 the pipe. However, specifying EOwnerThread as the second parameter to this function, |
|
187 means that only the opening thread can use this handle to write to the pipe. |
|
188 |
|
189 @param aReader Handle to the reading end of the pipe. |
|
190 |
|
191 @param aType The type of the handle to be created for the write end |
|
192 |
|
193 @return KErrNone Pipe successfully created, |
|
194 KErrInUse The current handle has already been opened |
|
195 KErrAccessDenied The read handle is not open for reading |
|
196 otherwise of the other system wide error code. |
|
197 */ |
|
198 { |
|
199 // Check if the current handle is already opened for reading/writing |
|
200 if ( iHandle && HandleType()) |
|
201 return KErrInUse; |
|
202 |
|
203 // Check the read handle |
|
204 |
|
205 if (aReader.HandleType() != EReadChannel) |
|
206 return KErrAccessDenied; |
|
207 |
|
208 // Perform the capability check and create the channel |
|
209 TInt err = DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL, aType, ETrue); |
|
210 if (err!= KErrNone) |
|
211 return err; |
|
212 |
|
213 // Obtained the handle number |
|
214 TInt id = aReader.PipeHandle(); |
|
215 |
|
216 |
|
217 // Set the Write channel |
|
218 err = DoControl(EOpenUnNamedPipe,(TAny*)&id); |
|
219 |
|
220 if( err == KErrNone) |
|
221 { |
|
222 iSize = DoControl(ESize); |
|
223 iHandleType = EWriteChannel; |
|
224 iPipeHandle = id; |
|
225 |
|
226 } |
|
227 else |
|
228 { |
|
229 Close(); |
|
230 } |
|
231 |
|
232 |
|
233 return err; |
|
234 } |
|
235 |
|
236 |
|
237 // Methods to Support Named Pipe |
|
238 |
|
239 EXPORT_C TInt RPipe::Define(const TDesC& aName, TInt aSize) |
|
240 /** |
|
241 Static method to create a new, named pipe of a given size. Calling this method |
|
242 will create a new kernel object only. No user-side handles are created or opened. |
|
243 |
|
244 @param aName Name to be assigned to the Kernel-side pipe object. |
|
245 @param aSize Size of the pipe to create, in bytes. |
|
246 |
|
247 @return KErrNone Pipe successfully created. |
|
248 KErrBadName If the length of aName is greater than KMaxFileName |
|
249 or Null |
|
250 KErrOverflow Maximum number of pipes has been reached |
|
251 KErrNoMemory Insufficient memory to create pipe. |
|
252 KErrArgument if Size is negative |
|
253 KErrAlreadyExist If a pipe with the specified name already exist. |
|
254 otherwise one of the other system wide error code. |
|
255 */ |
|
256 { |
|
257 // Code to check a valid Name field as per Symbian naming convention |
|
258 TInt err = User::ValidateName(aName); |
|
259 if(KErrNone!=err) |
|
260 return err; |
|
261 |
|
262 if((aName.Length() > KMaxKernelName) || (aName.Length() == 0)) |
|
263 return KErrBadName; |
|
264 |
|
265 if(aSize <= 0) |
|
266 return KErrArgument; |
|
267 |
|
268 // Perform the capability check and create the channel |
|
269 RPipe temp; |
|
270 err = temp.DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL); |
|
271 if (err!= KErrNone) |
|
272 return err; |
|
273 |
|
274 // Define |
|
275 TPipeInfoBuf aInfo; |
|
276 aInfo().isize = aSize; |
|
277 aInfo().iName.Copy(aName); |
|
278 |
|
279 // Define the Named pipe |
|
280 err = temp.DoControl(EDefineNamedPipe, (TAny*)&aInfo); |
|
281 temp.Close(); |
|
282 return err; |
|
283 |
|
284 } |
|
285 |
|
286 |
|
287 EXPORT_C TInt RPipe::Define( const TDesC& aName, TInt aSize, const TSecurityPolicy& aPolicy) |
|
288 /** |
|
289 Static method to create a new, named pipe of a given size. Calling this method |
|
290 will create a new kernel object only. No user-side handles are created or opened. |
|
291 |
|
292 @param aName Name to be assigned to the Kernel-side pipe object. |
|
293 @param aSize Size of the pipe to create, in bytes. |
|
294 |
|
295 @return KErrNone Pipe successfully created. |
|
296 KErrBadName If the length of aName is greater than KMaxFileName |
|
297 or Null |
|
298 KErrOverflow Maximum number of pipes has been reached |
|
299 KErrNoMemory Insufficient memory to create pipe. |
|
300 KErrArgument if Size is negative |
|
301 KErrPermissionDenied Not sufficient capabiliites |
|
302 KErrAlreadyExist If a pipe with the specified name already exist. |
|
303 otherwise one of the other system wide error code. |
|
304 */ |
|
305 { |
|
306 |
|
307 // Code to check a valid Name field as per Symbian naming convention |
|
308 TInt err = User::ValidateName(aName); |
|
309 if(KErrNone!=err) |
|
310 return err; |
|
311 |
|
312 if((aName.Length() > KMaxKernelName) || (aName.Length() == 0)) |
|
313 return KErrBadName; |
|
314 |
|
315 if(aSize <= 0) |
|
316 return KErrArgument; |
|
317 |
|
318 // Perform the capability check and create the channel |
|
319 RPipe temp; |
|
320 err = temp.DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL); |
|
321 if (err!= KErrNone) |
|
322 return err; |
|
323 |
|
324 // Define |
|
325 TPipeInfoBuf aInfo; |
|
326 aInfo().isize = aSize; |
|
327 aInfo().iName.Copy(aName); |
|
328 err = temp.DoControl(EDefineNamedPipe, (TAny*)&aInfo, (TAny*)&aPolicy); |
|
329 temp.Close(); |
|
330 |
|
331 return err; |
|
332 |
|
333 |
|
334 } |
|
335 |
|
336 |
|
337 |
|
338 EXPORT_C TInt RPipe::Destroy( const TDesC& aName) |
|
339 /** |
|
340 Static method to destroy a previously created named pipe. Any data not read from |
|
341 the pipe will be discarded. This method will fail if there is any handles still |
|
342 open on the pipe or the calling thread as insufficient capabilities. |
|
343 |
|
344 @param aName Name of the Kernel-side pipe object to destroy |
|
345 |
|
346 @return KErrNone Pipe successfully destroyed |
|
347 KErrInUse The pipe still has one or more handle open to it |
|
348 KErrPermissionDenied Not sufficient capabiliites |
|
349 KErrNotFound If no kernel pipe exist with the specified name |
|
350 otherwise one of the other system wide error code. |
|
351 */ |
|
352 { |
|
353 // Code to check a valid Name field as per Symbian naming convention |
|
354 TInt err = User::ValidateName(aName); |
|
355 if(KErrNone!=err) |
|
356 return err; |
|
357 |
|
358 if((aName.Length() > KMaxKernelName) || (aName.Length() == 0)) |
|
359 return KErrBadName; |
|
360 |
|
361 // Perform the capability check and create the channel |
|
362 RPipe temp; |
|
363 err = temp.DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL); |
|
364 if (err!= KErrNone) |
|
365 return err; |
|
366 |
|
367 TBuf8<KMaxKernelName> name; |
|
368 name.Copy(aName); |
|
369 |
|
370 // Destroy |
|
371 err = temp.DoControl(EDestroyNamedPipe, (TAny*)&name, NULL); |
|
372 temp.Close(); |
|
373 |
|
374 return err; |
|
375 |
|
376 } |
|
377 |
|
378 |
|
379 EXPORT_C TInt RPipe::Open(const TDesC& aName, TMode aMode) |
|
380 /** |
|
381 Opens the pipe for the access mode specified. If the handle is opened to read or Write. |
|
382 The handle is opened regardless of whether or not there is a open handle at the other end. |
|
383 |
|
384 If the handle is opened as " Write but Fail On No Readers" the call will fail unless there |
|
385 is atleast one handle open for reading at the other end. |
|
386 |
|
387 @param aName Name of the kernel-side pipe object to destroy |
|
388 @param aMode Access mode for the handle. |
|
389 |
|
390 @return KErrNone Handle successfully opened. |
|
391 KErrBadName If the length of aName is greater than KMaxFileName or Null |
|
392 KErrInUse The pipe still has one or more handle open to it. |
|
393 KErrPermissionDenied Not sufficient capabiliites |
|
394 KErrNotFond If there is no kernel instance with the specified name |
|
395 KErrNotReady Open Fails when no Readers is available while opening |
|
396 With TMode = EOpenToWriteButFailOnNoReaders |
|
397 otherwise one of the other system wide error code. |
|
398 |
|
399 */ |
|
400 { |
|
401 |
|
402 // Check if the current handle is already opened for reading/writing |
|
403 if ( iHandle && HandleType()) |
|
404 return KErrInUse; |
|
405 |
|
406 TInt err = User::ValidateName(aName); |
|
407 if(KErrNone!=err) |
|
408 return err; |
|
409 |
|
410 if((aName.Length() > KMaxKernelName) || (aName.Length() == 0)) |
|
411 return KErrBadName; |
|
412 |
|
413 // Perform the capability check and create the channel |
|
414 err = DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL); |
|
415 if (err!= KErrNone) |
|
416 return err; |
|
417 |
|
418 TBuf8<KMaxKernelName> name; |
|
419 name.Copy(aName); |
|
420 |
|
421 |
|
422 if (aMode == EOpenToRead) |
|
423 { |
|
424 err = DoControl(EOpenToReadNamedPipe,(TAny*)&name); |
|
425 if(err == KErrNone) |
|
426 { |
|
427 iSize = DoControl(ESize); |
|
428 iHandleType = EReadChannel; |
|
429 } |
|
430 else |
|
431 Close(); |
|
432 } |
|
433 else if(aMode == EOpenToWrite) |
|
434 { |
|
435 err = DoControl(EOpenToWriteNamedPipe, (TAny*)&name); |
|
436 if(err == KErrNone) |
|
437 { |
|
438 iSize = DoControl(ESize); |
|
439 iHandleType = EWriteChannel; |
|
440 } |
|
441 else |
|
442 Close(); |
|
443 } |
|
444 else if (aMode == EOpenToWriteNamedPipeButFailOnNoReaders) |
|
445 { |
|
446 err = DoControl(EOpenToWriteButFailOnNoReaderNamedPipe, (TAny*)&name); |
|
447 if(err == KErrNone) |
|
448 { |
|
449 iSize = DoControl(ESize); |
|
450 iHandleType = EWriteChannel; |
|
451 } |
|
452 else |
|
453 Close(); |
|
454 } |
|
455 else |
|
456 { |
|
457 Close(); |
|
458 err = KErrArgument; |
|
459 } |
|
460 return err; |
|
461 } |
|
462 |
|
463 |
|
464 |
|
465 EXPORT_C void RPipe::Wait(const TDesC& aName, TRequestStatus& aStatus) |
|
466 /** |
|
467 Block the thread until the other end of the pipe is opened for reading. If the other end |
|
468 is already opened for reading the call will not block and status will complete immediately |
|
469 This function will be deprecated , use WaitForReader. |
|
470 Please note that Wait API will open a valid Write End of the pipe if not opened already. |
|
471 User need not open write end of the pipe again after Wait call. |
|
472 |
|
473 |
|
474 @param aName Name of the kernel-side pipe object to wait for |
|
475 @param aStatus Status request that will complete when the other end is opened |
|
476 for reading. |
|
477 |
|
478 @return KErrNone Request is successfully registered |
|
479 KErrBadName If the length of aName is greater then KMaxFileName or NULL |
|
480 KErrInUse A notifier of this type has already been registered. |
|
481 KErrPermissionDenied Not sufficient capabiliites |
|
482 otherwise one of the other system wide error code. |
|
483 */ |
|
484 { |
|
485 // To wait for Reader end pass flag as EWaitForReader. |
|
486 TInt aFlag = EWaitForReader; |
|
487 Wait(aName, aStatus , aFlag ); |
|
488 } |
|
489 |
|
490 |
|
491 EXPORT_C void RPipe::CancelWait() |
|
492 /** |
|
493 Cancel previous call to RPipe::Wait(), RPipe::WaitForReader (), RPipe::WaitForWriter () |
|
494 |
|
495 @param None |
|
496 @return None |
|
497 */ |
|
498 { |
|
499 if(!iHandle) |
|
500 return; |
|
501 DoCancel(ECancelWaitNotification); |
|
502 } |
|
503 |
|
504 |
|
505 |
|
506 // Generic Methods |
|
507 |
|
508 EXPORT_C void RPipe::Close() |
|
509 /** |
|
510 Close the handle. This method exhibits different behaviour depending upon whether the pipe |
|
511 is named or unnamed. |
|
512 Named pipes are allowed to persist without any open handles. Closing the last handle on a |
|
513 named pipe will not destroy the kernel-side object. For an unnamed pipe, closing the last |
|
514 handle will destroy the kernel-side pipe object. Any unread data in the pipe will be |
|
515 discarded. |
|
516 An attempt to close an unnamed pipe will have no effect. Closing a handle will not affect |
|
517 the state of any other handles that may be open on the pipe. |
|
518 |
|
519 @param None |
|
520 |
|
521 @return None |
|
522 */ |
|
523 { |
|
524 if(!iHandle) |
|
525 return; |
|
526 RHandleBase::Close(); |
|
527 } |
|
528 |
|
529 |
|
530 |
|
531 |
|
532 EXPORT_C TInt RPipe::MaxSize() |
|
533 /** |
|
534 Returns the total size, in bytes, of the Pipe |
|
535 @param None |
|
536 |
|
537 @return >= 0 Size of the pipe in bytes |
|
538 KErrBadHandle The handle is not open |
|
539 otherwise one of the other system wide error code. |
|
540 */ |
|
541 { |
|
542 if (!iHandle ) |
|
543 return KErrBadHandle; |
|
544 |
|
545 if(iHandleType == EReadChannel || iHandleType == EWriteChannel) |
|
546 return iSize; |
|
547 else |
|
548 return KErrAccessDenied; |
|
549 } |
|
550 |
|
551 |
|
552 |
|
553 EXPORT_C TInt RPipe::Read(TDes8& aMsg, TInt aNumByte) |
|
554 /** |
|
555 This is non-blocking synchronous method to read aNumByte bytes from the pipe into the |
|
556 descriptor aMsg and returns the number of bytes read. If the pipe is empty the call will |
|
557 immediately return a value of zero to indicate that no data was read |
|
558 |
|
559 A successful RPipe::Read() operation will free up more space in the pipe. |
|
560 |
|
561 @param aMsg Descriptor to receive data |
|
562 @param aNumByte Number of bytes to be received. |
|
563 |
|
564 @return >0 Amount of data read from the pipe, in bytes. |
|
565 KErrUnderFlow The pipe was empty, no data was read |
|
566 KErrAccessDenied An attempt has been made to read from a handle |
|
567 has been opened for writing. |
|
568 KErrBadHandle An attempt has been made to read from a handle |
|
569 that has not been opened. |
|
570 KErrNotReady Write end is closed and Pipe is empty. |
|
571 0 No Data is available |
|
572 otherwise one of the other system wide error code. |
|
573 */ |
|
574 { |
|
575 // Check for the error condition |
|
576 if (!iHandle) |
|
577 return KErrBadHandle; |
|
578 |
|
579 // Check for KErrArgument |
|
580 if(aNumByte > aMsg.MaxLength()) |
|
581 return KErrArgument; |
|
582 |
|
583 if(iHandleType != EReadChannel) |
|
584 return KErrAccessDenied; |
|
585 |
|
586 return DoControl(ERead, (TAny*)&aMsg, (TAny*)&aNumByte); |
|
587 } |
|
588 |
|
589 |
|
590 |
|
591 |
|
592 EXPORT_C TInt RPipe::Write( const TDesC8& aData, TInt aNumByte) |
|
593 /** |
|
594 This is non-blocking synchronous method to write data from aData. If the pipe is |
|
595 full it will return immediately with KErrOverFlow |
|
596 |
|
597 @param aData Descriptor from which data has to be written to the pipe |
|
598 |
|
599 @return >0 Amount of data written to the pipe, in bytes |
|
600 KErrAccessDenied An attempt has been made to write to a handle that |
|
601 has been opened for reading. |
|
602 KErrArgument If the size is more then aData's length |
|
603 KErrBadName |
|
604 KErrOverFlow The pipe is full. No data was inserted into the pipe. |
|
605 KErrBadHandle An attempt has been made to read from a handle that |
|
606 has not been opened. |
|
607 KErrCompletion If the specified size is greater then the available size. |
|
608 KErrNotReady Read end is closed. |
|
609 otherwise one of the other system wide error code. |
|
610 |
|
611 */ |
|
612 { |
|
613 // Check for the error condition |
|
614 if (!iHandle) |
|
615 return KErrBadHandle; |
|
616 |
|
617 // Check for KErrArgument |
|
618 if(aNumByte > aData.Length()) |
|
619 return KErrArgument; |
|
620 |
|
621 if(iHandleType == EReadChannel) |
|
622 return KErrAccessDenied; |
|
623 |
|
624 return DoControl(EWrite, (TAny*)&aData, (TAny*)&aNumByte); |
|
625 |
|
626 } |
|
627 |
|
628 |
|
629 EXPORT_C TInt RPipe::ReadBlocking( TDes8& aMsg, TInt aNumByte) |
|
630 /** |
|
631 This is synchronous, blocking read operation. If the pipe is empty the client thread will |
|
632 be blocked until data become available. A successful RPipe::ReadBlocking() operation will |
|
633 free up more space in the pipe. This method is accompanied by data notification method to |
|
634 complete the blocking mechanism |
|
635 |
|
636 @param aMsg Descriptor to receive data |
|
637 @param aNumByte Number of bytes to be received |
|
638 |
|
639 @return >0 Amount of data read from the pipe in bytes. |
|
640 KErrAccessDenied Am attempt has been made to read from the handle that |
|
641 has been opened for writing. |
|
642 KErrBadHandle Am attempt has been made to read from a handle that has |
|
643 not been opened. |
|
644 KErrArgument if the size is negative. |
|
645 KErrInUse If the call is active from some another thread. |
|
646 KErrNotReady Write end is closed and Pipe is empty. |
|
647 otherwise one of the system wide error code. |
|
648 */ |
|
649 { |
|
650 |
|
651 TRequestStatus stat = KRequestPending; |
|
652 TInt err = KErrNone; |
|
653 |
|
654 // Check for the error condition |
|
655 if (!iHandle) |
|
656 return KErrBadHandle; |
|
657 |
|
658 if(aNumByte <= 0) |
|
659 return KErrArgument; |
|
660 |
|
661 if(iHandleType != EReadChannel) |
|
662 return KErrAccessDenied; |
|
663 |
|
664 // Asynchronous request to notify the data available. |
|
665 do |
|
666 { |
|
667 stat = KRequestPending; |
|
668 DoRequest(EReadBlocking, stat); |
|
669 User::WaitForRequest(stat); |
|
670 err = stat.Int(); |
|
671 if (err == KErrInUse || err == KErrNotReady) |
|
672 { |
|
673 return err; |
|
674 } |
|
675 |
|
676 // Synchronous read operation |
|
677 err = DoControl(ERead, (TAny*)&aMsg, (TAny*)&aNumByte); |
|
678 if (err == KErrNotReady) |
|
679 return err; |
|
680 |
|
681 } while (err == 0); |
|
682 |
|
683 return err; |
|
684 } |
|
685 |
|
686 |
|
687 |
|
688 EXPORT_C TInt RPipe::WriteBlocking(const TDesC8& aData, TInt aNumByte) |
|
689 /** |
|
690 This is a synchronous, blocking write operation. It will attempt to |
|
691 write aNumByte's worth of data to the pipe, waiting till space is available. |
|
692 If aNumByte is less than or equal to the pipe size, MaxSize(), the write |
|
693 shall be atomic (w.r.t other threads sharing this channel), otherwise |
|
694 the data will be split into multiple atomic writes of pipe size |
|
695 (except, of course, if less than MaxSize bytes of data remain to be written). |
|
696 |
|
697 @param aData Descriptor from which data has to be written to the pipe. |
|
698 @param aNumByte Amount of data to be written to the pipe |
|
699 |
|
700 @return >0 Amount of data written to the pipe, in bytes. |
|
701 KErrAccessDenied An attempt has been made to write to a handle that |
|
702 has been opened for reading. |
|
703 KErrBadHandle An attempt has been made to read from a handle that has |
|
704 not been open. |
|
705 KErrArgument if the size is negative. |
|
706 KErrNotReady Read end is closed. |
|
707 otherwise one of the other system wide error code. |
|
708 */ |
|
709 { |
|
710 TBool first = ETrue; |
|
711 TRequestStatus stat = KRequestPending; |
|
712 TInt err = 0; |
|
713 TInt index = 0; |
|
714 TInt writeindex =0; |
|
715 TPtrC8 tmp; |
|
716 TInt r = aNumByte; |
|
717 |
|
718 // Check for the error condition |
|
719 if (!iHandle) |
|
720 return KErrBadHandle; |
|
721 |
|
722 |
|
723 if(aNumByte <= 0) |
|
724 return KErrArgument; |
|
725 |
|
726 |
|
727 if(iHandleType == EReadChannel) |
|
728 return KErrAccessDenied; |
|
729 |
|
730 if (aNumByte <= iSize) |
|
731 writeindex = aNumByte; |
|
732 else |
|
733 writeindex = iSize; |
|
734 |
|
735 do |
|
736 { |
|
737 // Asynchronous request to notify the space available. |
|
738 stat = KRequestPending; |
|
739 DoRequest(EWriteBlocking, stat,(TAny*)&writeindex); |
|
740 User::WaitForRequest(stat); |
|
741 err = stat.Int(); |
|
742 if (err == KErrInUse || err == KErrNotReady) |
|
743 { |
|
744 return err; |
|
745 } |
|
746 |
|
747 // Synchronous write operation |
|
748 tmp.Set(aData.Ptr()+index, writeindex); |
|
749 err = DoControl(EWrite, (TAny*)&tmp, (TAny*)&writeindex); |
|
750 if(err == KErrNotReady) |
|
751 { |
|
752 return err; |
|
753 } |
|
754 else |
|
755 { |
|
756 if ( err == aNumByte) |
|
757 { |
|
758 first = EFalse; |
|
759 } |
|
760 else |
|
761 { |
|
762 index = index + err; |
|
763 aNumByte = r - index; |
|
764 if(aNumByte < iSize) |
|
765 writeindex = aNumByte; |
|
766 } |
|
767 } |
|
768 }while(first); |
|
769 |
|
770 return r; |
|
771 } |
|
772 |
|
773 |
|
774 EXPORT_C void RPipe::NotifyDataAvailable(TRequestStatus& aStatus) |
|
775 /** |
|
776 This method registers the request status object to be completed when data become |
|
777 available in the pipe. |
|
778 |
|
779 @param aStatus Status request that will complete when Data is available. |
|
780 |
|
781 @return KErrNone Successfully registered. |
|
782 KErrAccessDenied Am attempt has been made to register a space available |
|
783 notification on a handle that has not been opened for |
|
784 reading. |
|
785 KErrCompletion The request was NOT registered as the condition succeeded before wait. |
|
786 KErrBadHandle The handle is not yet associated with a kernel pipe |
|
787 otherwise of the other system wide error code. |
|
788 |
|
789 |
|
790 */ |
|
791 { |
|
792 TInt err = KErrNone; |
|
793 if(!iHandle) |
|
794 { |
|
795 err = KErrBadHandle; |
|
796 } |
|
797 else if(iHandleType != EReadChannel) |
|
798 { |
|
799 err = KErrAccessDenied; |
|
800 } |
|
801 if(err!= KErrNone) |
|
802 { |
|
803 ReqComplete(aStatus, err); |
|
804 return; |
|
805 } |
|
806 aStatus = KRequestPending; |
|
807 DoRequest(EDataAvailable, aStatus); |
|
808 } |
|
809 |
|
810 |
|
811 |
|
812 |
|
813 EXPORT_C void RPipe::NotifySpaceAvailable(TInt aSize, TRequestStatus& aStatus) |
|
814 /** |
|
815 This method registers the request status object to be completed when at least |
|
816 aSize bytes are available for writing data into the pipe. |
|
817 |
|
818 @param aSize Amount of space to wait for in the pipe. |
|
819 @param aStatus Status request that will complete when aSize |
|
820 bytes become available. |
|
821 |
|
822 @returns KErrNone Successfully registered. |
|
823 KErrAccessDenied An attempt has been made to register a space |
|
824 available notification on a handle that has |
|
825 not been opened for writing. |
|
826 KErrArgument If the size is negative, zero, or greater than maximum pipe size |
|
827 KErrBadHandle The handle is not yet associated with a kernel pipe |
|
828 otherwise one of the other system wide error code |
|
829 |
|
830 |
|
831 */ |
|
832 { |
|
833 |
|
834 TInt err = KErrNone; |
|
835 if(!iHandle) |
|
836 { |
|
837 err = KErrBadHandle; |
|
838 } |
|
839 else if(iHandleType == EReadChannel) |
|
840 { |
|
841 err = KErrAccessDenied; |
|
842 } |
|
843 else if(aSize <= 0 || aSize > MaxSize()) |
|
844 { |
|
845 err = KErrArgument; |
|
846 } |
|
847 |
|
848 if(err!= KErrNone) |
|
849 { |
|
850 ReqComplete(aStatus, err); |
|
851 return; |
|
852 } |
|
853 aStatus = KRequestPending; |
|
854 DoRequest(ESpaceAvailable, aStatus, (TAny*)&aSize); |
|
855 } |
|
856 |
|
857 |
|
858 |
|
859 |
|
860 EXPORT_C TInt RPipe::CancelSpaceAvailable() |
|
861 /** |
|
862 Cancels an outstanding space available notifier request. |
|
863 |
|
864 @param None |
|
865 |
|
866 @returns KErrNone Successfully cancelled the SpaceAvailable request. |
|
867 KErrBadHandle An attempt has been made to Cancel Data Available with a |
|
868 handle which has not been associated with any kernel pipe. |
|
869 KErrAccessDenied An attempt has been made to cancel a space available |
|
870 notification on a handle that has been opened for reading. |
|
871 other wise on of the other system wide error code. |
|
872 */ |
|
873 { |
|
874 if(!iHandle) |
|
875 return KErrBadHandle; |
|
876 |
|
877 if(iHandleType != EWriteChannel) |
|
878 return KErrAccessDenied; |
|
879 |
|
880 DoCancel(ECancelSpaceAvailable); |
|
881 |
|
882 return KErrNone; |
|
883 } |
|
884 |
|
885 |
|
886 |
|
887 EXPORT_C TInt RPipe::CancelDataAvailable() |
|
888 /** |
|
889 Cancels an outstanding data available notifier request. |
|
890 |
|
891 @param None |
|
892 @return KErrNone Successfully cancelled the DataAvailable request. |
|
893 KErrBadHandle An attempt has been made to Cancel Data Available with a |
|
894 handle which has not been associated with any kernel pipe. |
|
895 KErrAccessDenied Am attempt has been made to cancel a data available |
|
896 notification on a handle that has been opened for writing. |
|
897 otherwise one of the other system wide error code |
|
898 */ |
|
899 { |
|
900 if(!iHandle) |
|
901 return KErrBadHandle; |
|
902 |
|
903 if(iHandleType != EReadChannel) |
|
904 return KErrAccessDenied; |
|
905 |
|
906 DoCancel(ECancelDataAvailable); |
|
907 |
|
908 return KErrNone; |
|
909 } |
|
910 |
|
911 |
|
912 EXPORT_C void RPipe::Flush() |
|
913 /** |
|
914 This method will empty the pipe of all data |
|
915 |
|
916 @param None |
|
917 @returns None |
|
918 */ |
|
919 { |
|
920 DoControl(EFlushPipe); |
|
921 } |
|
922 |
|
923 |
|
924 EXPORT_C TInt RPipe::HandleType()const |
|
925 /** |
|
926 This method returns the Type of operation it can perform with the current handle. |
|
927 @param None |
|
928 @returns |
|
929 EReadChannel If the current handle is associated to the kernel-side |
|
930 pipe object as to perform Read operations. |
|
931 EWriteChannel If the current handle is associated to the kernel-side |
|
932 pipe object as to perform Write operations. |
|
933 KErrBadHandle If the handle is not associated with Kernel-side object. |
|
934 otherwise one of the other system wide error code |
|
935 */ |
|
936 { |
|
937 if(!iHandle) |
|
938 return KErrBadHandle; |
|
939 else |
|
940 return iHandleType; |
|
941 } |
|
942 |
|
943 |
|
944 EXPORT_C TInt RPipe::Size() |
|
945 /** |
|
946 Returns the available data in the pipe |
|
947 @param None |
|
948 @return >= 0 Amount of data available in the pipe |
|
949 KErrBadHandle The handle is not yet opened |
|
950 otherwise one of the other system wide error code. |
|
951 |
|
952 */ |
|
953 { |
|
954 if(!iHandle) |
|
955 return KErrBadHandle; |
|
956 |
|
957 return DoControl(EDataAvailableCount); |
|
958 } |
|
959 |
|
960 |
|
961 TInt RPipe::PipeHandle()const |
|
962 /** |
|
963 Returns the id of Pipe it has created. |
|
964 */ |
|
965 { |
|
966 return iPipeHandle; |
|
967 } |
|
968 |
|
969 |
|
970 void RPipe::ReqComplete(TRequestStatus& aStatus, TInt err) |
|
971 { |
|
972 TRequestStatus* req=(&aStatus); |
|
973 User::RequestComplete(req,err); |
|
974 } |
|
975 |
|
976 EXPORT_C void RPipe::WaitForReader(const TDesC& aName, TRequestStatus& aStatus) |
|
977 /** |
|
978 Block the thread until the other end of the pipe is opened for reading. If the other end |
|
979 is already opened for reading the call will not block and status will complete immediately. |
|
980 |
|
981 Please note that WaitForReader API will open a valid Write End of the pipe if not opened already. |
|
982 User need not open write end of the pipe again after WaitForReader call. |
|
983 |
|
984 @param aName Name of the kernel-side pipe object to wait for |
|
985 @param aStatus Status request that will complete when the other end is opened |
|
986 for reading. |
|
987 |
|
988 @return KErrNone Request is successfully registered |
|
989 KErrBadName If the length of aName is greater then KMaxFileName or NULL |
|
990 KErrInUse A notifier of this type has already been registered. |
|
991 KErrPermissionDenied Not sufficient capabiliites |
|
992 KErrAccessDenied WaitForReader request is issued using Read handle. |
|
993 otherwise one of the other system wide error code. |
|
994 */ |
|
995 { |
|
996 // To wait for Reader end pass flag as EWaitForReader. |
|
997 TInt aFlag = EWaitForReader; |
|
998 Wait(aName, aStatus , aFlag ); |
|
999 } |
|
1000 |
|
1001 EXPORT_C void RPipe::WaitForWriter(const TDesC& aName, TRequestStatus& aStatus) |
|
1002 /** |
|
1003 Block the thread until the other end of the pipe is opened for writing. If the other end |
|
1004 is already opened for writing the call will not block and status will complete immediately |
|
1005 |
|
1006 Please note that WaitForWriter API will open a valid Read End of the pipe if not opened already. |
|
1007 User need not open read end of the pipe again after WaitForWriter call. |
|
1008 |
|
1009 @param aName Name of the kernel-side pipe object to wait for |
|
1010 @param aStatus Status request that will complete when the other end is opened |
|
1011 for writing. |
|
1012 |
|
1013 @return KErrNone Request is successfully registered |
|
1014 KErrBadName If the length of aName is greater then KMaxFileName or NULL |
|
1015 KErrInUse A notifier of this type has already been registered. |
|
1016 KErrPermissionDenied Not sufficient capabiliites |
|
1017 KErrAccessDenied WaitForWriter request is issued using Write handle. |
|
1018 otherwise one of the other system wide error code. |
|
1019 */ |
|
1020 { |
|
1021 // To wait for Writer end pass flag as EWaitForWriter. |
|
1022 TInt aFlag = EWaitForWriter; |
|
1023 Wait(aName, aStatus , aFlag ); |
|
1024 } |
|
1025 |
|
1026 |
|
1027 void RPipe::Wait(const TDesC& aName, TRequestStatus& aStatus , TInt aChoice) |
|
1028 /** |
|
1029 Block the thread until the other end of the pipe is opened for reading (or writing). If the other end |
|
1030 is already opened for reading (or writing) the call will not block and status will complete immediately. |
|
1031 |
|
1032 |
|
1033 |
|
1034 @param aName Name of the kernel-side pipe object to wait for |
|
1035 @param aStatus Status request that will complete when the other end is opened |
|
1036 for reading (or Writing). |
|
1037 @param aChoice EWaitForReader for WaitForReader. |
|
1038 EWaitForWriter for WaitForWriter. |
|
1039 |
|
1040 @return KErrNone Request is successfully registered |
|
1041 KErrBadName If the length of aName is greater then KMaxFileName or NULL |
|
1042 KErrInUse A notifier of this type has already been registered. |
|
1043 KErrPermissionDenied Not sufficient capabiliites |
|
1044 KErrAccessDenied WaitForReader request is issued using Read handle or |
|
1045 WaitForWriter request is issued using Write handle. |
|
1046 otherwise one of the other system wide error code. |
|
1047 */ |
|
1048 { |
|
1049 |
|
1050 // Code to check a valid Name field as per Symbian naming convention |
|
1051 TInt err = User::ValidateName(aName); |
|
1052 if(err != KErrNone) |
|
1053 { |
|
1054 ReqComplete(aStatus, err); |
|
1055 return; |
|
1056 } |
|
1057 |
|
1058 if((aName.Length() > KMaxKernelName) || (aName.Length() == 0)) |
|
1059 { |
|
1060 ReqComplete(aStatus, KErrBadName); |
|
1061 return; |
|
1062 } |
|
1063 |
|
1064 TBuf8<KMaxKernelName> name8; |
|
1065 name8.Copy(aName); |
|
1066 |
|
1067 aStatus = KRequestPending; |
|
1068 // Check if the current instance of RPipe is already opened. |
|
1069 if (!iHandle) |
|
1070 { |
|
1071 // Perform the capability check and create the channel |
|
1072 err = DoCreate(Name(),VersionRequired(), KNullUnit, NULL, NULL); |
|
1073 if (err!= KErrNone) |
|
1074 { |
|
1075 ReqComplete(aStatus, err); |
|
1076 return; |
|
1077 } |
|
1078 |
|
1079 if (aChoice == EWaitForReader) |
|
1080 { |
|
1081 // Open the Write handle. |
|
1082 err = DoControl(EOpenToWriteNamedPipe, (TAny*)&name8); |
|
1083 if(err == KErrNone) |
|
1084 { |
|
1085 iSize = DoControl(ESize); |
|
1086 iHandleType = EWriteChannel; |
|
1087 } |
|
1088 } |
|
1089 else |
|
1090 { |
|
1091 // Open the Read handle. |
|
1092 err = DoControl(EOpenToReadNamedPipe, (TAny*)&name8); |
|
1093 if(err == KErrNone) |
|
1094 { |
|
1095 iSize = DoControl(ESize); |
|
1096 iHandleType = EReadChannel; |
|
1097 } |
|
1098 } |
|
1099 |
|
1100 if ( err!= KErrNone) |
|
1101 { |
|
1102 Close(); |
|
1103 ReqComplete(aStatus, err); |
|
1104 return; |
|
1105 } |
|
1106 } |
|
1107 // use the existing Logical channel to send the request. |
|
1108 DoRequest(EWaitNotification, aStatus, (TAny*)&name8,(TAny*)&aChoice); |
|
1109 } |
|
1110 |
|
1111 |