|
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 // Client interface to the CPosixServer |
|
15 // |
|
16 // |
|
17 |
|
18 #include "POSIXIF.H" |
|
19 #include "LTIME.H" |
|
20 #include "LPOSIX.H" |
|
21 #include <fcntl.h> |
|
22 #include <sys/errno.h> |
|
23 #include <sys/serial.h> |
|
24 #include <sys/wait.h> |
|
25 |
|
26 |
|
27 #ifdef _DEBUG |
|
28 #define DebugPrint RDebug::Print |
|
29 #else |
|
30 inline void DebugPrint(const TDesC&, ...) {} |
|
31 #endif |
|
32 |
|
33 // RPosixSession |
|
34 // |
|
35 // The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams |
|
36 // in p[1]. The result is written back into the PosixParams.retval field. |
|
37 |
|
38 int RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams) const |
|
39 { |
|
40 return SendReceive(aFunction,TIpcArgs(&anErrno,&aParams)); |
|
41 } |
|
42 |
|
43 void RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams, TRequestStatus& aStatus) const |
|
44 { |
|
45 SendReceive(aFunction,TIpcArgs(&anErrno,&aParams),aStatus); // asynchronous request |
|
46 } |
|
47 |
|
48 void RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg,TRequestStatus &aStatus) const |
|
49 { |
|
50 RSessionBase::SendReceive(aFunction,aArg,aStatus); |
|
51 } |
|
52 TInt RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg) const |
|
53 { |
|
54 return RSessionBase::SendReceive(aFunction,aArg); |
|
55 } |
|
56 |
|
57 TVersion RPosixSession::Version() |
|
58 { |
|
59 return TVersion(KCPosixMajorVersionNumber,KCPosixMinorVersionNumber,0); |
|
60 } |
|
61 |
|
62 TInt RPosixSession::Connect (TDesC& aServerName) |
|
63 { |
|
64 TVersion version=Version(); |
|
65 return CreateSession(aServerName,version,1+3); // 3 extra message slots for pipes |
|
66 } |
|
67 |
|
68 TInt RPosixSession::Connect () |
|
69 { |
|
70 TBuf<80> serverName; |
|
71 PosixServerName(serverName); |
|
72 return CreateSession(serverName,Version(),1); |
|
73 } |
|
74 |
|
75 // CPosixServer support functions exported from ESTLIB.DLL |
|
76 |
|
77 #if defined(__WINS__) |
|
78 |
|
79 // simple scheme to provide pretend processes on WINS |
|
80 |
|
81 extern "C" void getcwd(char*,int); |
|
82 typedef void (*FUNC)(); |
|
83 |
|
84 static int id=1; |
|
85 EXPORT_C void NewProcessId () |
|
86 { |
|
87 id += 10; |
|
88 } |
|
89 |
|
90 static FUNC procFn; |
|
91 EXPORT_C void NextProcessFn (TAny* aFn) |
|
92 { |
|
93 procFn=(FUNC)aFn; |
|
94 } |
|
95 |
|
96 TInt threadhelper (TAny* aFn) |
|
97 { |
|
98 CTrapCleanup::New(); |
|
99 FUNC f=(FUNC)aFn; |
|
100 (*f)(); |
|
101 return 0; |
|
102 } |
|
103 TInt processhelper (TAny*) |
|
104 { |
|
105 // Do the MCRT0.OBJ things straight away |
|
106 SpawnPosixServerThread(); |
|
107 char wd[80]; |
|
108 getcwd(wd, sizeof(wd)); // connect to CPosixServer |
|
109 return threadhelper(procFn); |
|
110 } |
|
111 #endif // __WINS__ |
|
112 _LIT(SERVER_FORMAT,"Posix-%d"); |
|
113 _LIT(SERVER_MATCH, "Posix-*"); |
|
114 |
|
115 EXPORT_C void PosixServerName(TDes& aBuffer) |
|
116 // |
|
117 // Construct the name of the CPosixServer for this process |
|
118 // |
|
119 { |
|
120 TProcessId id=RProcess().Id(); |
|
121 aBuffer.Format(SERVER_FORMAT,*REINTERPRET_CAST(int*,&id)); |
|
122 } |
|
123 |
|
124 struct rendezvous |
|
125 { |
|
126 RThread iCaller; |
|
127 TRequestStatus* iStatus; |
|
128 }; |
|
129 |
|
130 EXPORT_C TInt SpawnPosixServerThread () |
|
131 // |
|
132 // Try to start a PosixServer thread, assuming there isn't one already |
|
133 // |
|
134 { |
|
135 RPosixSession probe; |
|
136 TInt err=probe.Connect(); |
|
137 probe.Close(); |
|
138 if (err==KErrNone) |
|
139 return KErrNone; // server already exists |
|
140 TBuf<80> serverName; |
|
141 PosixServerName(serverName); |
|
142 TRequestStatus status(KRequestPending); |
|
143 struct rendezvous rv; |
|
144 rv.iCaller.Duplicate(RThread(),EOwnerProcess); |
|
145 rv.iStatus=&status; |
|
146 RThread server; |
|
147 err=server.Create(serverName,CPosixServer::ThreadFunction,0x2000,NULL,&rv); |
|
148 if (err==KErrNone) |
|
149 { |
|
150 server.Resume(); |
|
151 User::WaitForRequest(status); |
|
152 err=status.Int(); |
|
153 server.Close(); |
|
154 } |
|
155 rv.iCaller.Close(); |
|
156 return err; |
|
157 } |
|
158 |
|
159 EXPORT_C TInt InstallPosixServerActiveObject (TInt aPriority) |
|
160 { |
|
161 TRAPD(err, CPosixServer::InitL(aPriority)); |
|
162 return err; |
|
163 } |
|
164 |
|
165 void CPosixServer::InitL(TInt aPriority) |
|
166 // |
|
167 // Construct and install a CPosixServer active object |
|
168 // |
|
169 { |
|
170 CPosixServer *pS=new(ELeave) CPosixServer(aPriority); |
|
171 CleanupStack::PushL(pS); |
|
172 TBuf<80> serverName; |
|
173 PosixServerName(serverName); |
|
174 |
|
175 User::LeaveIfError(pS->iFs.Connect()); |
|
176 |
|
177 pS->iFids.InitL(); |
|
178 |
|
179 // search for parent process |
|
180 pS->FindParentL(); |
|
181 |
|
182 // set up default fids |
|
183 pS->DefaultConsoleL(); |
|
184 |
|
185 DebugPrint(_L("Starting CPosixServer\n")); |
|
186 pS->StartL(serverName); |
|
187 CleanupStack::Pop(pS); |
|
188 // Leave pS on the clean up stack for the calling routine to clean up normally on |
|
189 // Active Scheduler shutdown or in a failure case where the scheduler does not |
|
190 // start due to an error. |
|
191 |
|
192 } |
|
193 |
|
194 // CPosixServer |
|
195 |
|
196 CPosixServer::CPosixServer(TInt aPriority) |
|
197 : CServer2(aPriority) |
|
198 { |
|
199 __DECLARE_NAME(_S("CPosixServer")); |
|
200 } |
|
201 |
|
202 TInt CPosixServer::ThreadFunction(TAny* aPtr) |
|
203 // |
|
204 // Create and run an active scheduler containing a CPosixServer |
|
205 // |
|
206 { |
|
207 CTrapCleanup* TheTrapCleanup=CTrapCleanup::New(); |
|
208 |
|
209 RLibrary stdlib; |
|
210 stdlib.Load(_L("estlib")); // workaround for RAM-loaded EXE calling RAM-loaded DLL |
|
211 |
|
212 struct rendezvous* rvp = (struct rendezvous *)aPtr; |
|
213 TInt ret=KErrNone; |
|
214 // start scheduler and server |
|
215 CActiveScheduler *pA=new CActiveScheduler; |
|
216 if (pA!=NULL) |
|
217 { |
|
218 CActiveScheduler::Install(pA); |
|
219 ret=InstallPosixServerActiveObject(); |
|
220 } |
|
221 // signal to the caller that we've started (or failed!) |
|
222 rvp->iCaller.RequestComplete(rvp->iStatus,ret); |
|
223 if (ret==KErrNone) |
|
224 { |
|
225 // start fielding requests from clients |
|
226 CActiveScheduler::Start(); |
|
227 } |
|
228 // finished |
|
229 delete TheTrapCleanup; |
|
230 return(KErrNone); |
|
231 } |
|
232 |
|
233 CSession2* CPosixServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const |
|
234 { |
|
235 TBool r=User::QueryVersionSupported(RPosixSession::Version(),aVersion); |
|
236 if (!r) |
|
237 User::Leave(KErrNotSupported); |
|
238 |
|
239 RProcess clientProcess; |
|
240 RThread clientThread; |
|
241 User::LeaveIfError(aMessage.Client(clientThread)); |
|
242 CleanupClosePushL(clientThread); |
|
243 User::LeaveIfError(clientThread.Process(clientProcess)); |
|
244 TProcessId clientId = clientProcess.Id(); |
|
245 clientProcess.Close(); |
|
246 CleanupStack::PopAndDestroy(1); //close thread |
|
247 |
|
248 if (clientId!=RProcess().Id()) |
|
249 { |
|
250 // A thread in a different process |
|
251 if (iChildren==0) |
|
252 User::Leave(KErrNotReady); // quick rejection |
|
253 |
|
254 // We need an explicit CONST_CAST so that the CPosixRequest objects have a |
|
255 // mutable reference to the CPosixServer which holds the shared data structures |
|
256 return new(ELeave) CPosixIPCSession(CONST_CAST(CPosixServer&,*this)); |
|
257 } |
|
258 // A thread in the same process |
|
259 return new(ELeave) CPosixSession(CONST_CAST(CPosixServer&,*this)); |
|
260 } |
|
261 |
|
262 void CPosixServer::ServerPanic (TPosixServerPanic aPanic) |
|
263 { |
|
264 _LIT(KPosixServerPanic, "Posix server"); |
|
265 User::Panic(KPosixServerPanic,aPanic); |
|
266 } |
|
267 |
|
268 void CPosixServer::FindParentL() |
|
269 { |
|
270 TFullName parent; |
|
271 TPosixIPCPid pid; |
|
272 TPosixIPCReply reply; |
|
273 |
|
274 TProcessId id=RProcess().Id(); |
|
275 pid = *REINTERPRET_CAST(TUint*,&id); // my process id |
|
276 |
|
277 TFindServer posixservers(SERVER_MATCH); |
|
278 while (posixservers.Next(parent)==KErrNone) |
|
279 { |
|
280 DebugPrint(_L("Are you my mother, %S?"), &parent); |
|
281 if (iParent.Connect(parent)!=KErrNone) |
|
282 continue; |
|
283 if (iParent.Request(PMAreYouMyMother,TIpcArgs(&pid, &reply))!=KErrNone) |
|
284 { |
|
285 iParent.Close(); |
|
286 continue; |
|
287 } |
|
288 |
|
289 // found parent |
|
290 DebugPrint(_L("Found parent process %S"), &parent); |
|
291 |
|
292 // Create any pipes that might be required |
|
293 TUint mask=reply().iPipeMask; |
|
294 CPipeChildDesc* pipes[3]; |
|
295 TInt i=0; |
|
296 for (i=0; i<3; i++, mask>>=1) |
|
297 { |
|
298 pipes[i]=0; |
|
299 if (mask&1) |
|
300 { |
|
301 CPipeChildDesc* pipe=new(ELeave) CPipeChildDesc(i,iParent); |
|
302 pipes[i]=pipe; |
|
303 pipe->PushLC(); |
|
304 } |
|
305 } |
|
306 |
|
307 // organise the necessary descriptors |
|
308 TPtr env=HBufC::NewLC(reply().iEnvironmentSize)->Des(); |
|
309 TPtr cwd=HBufC::NewLC(reply().iWorkingDirectorySize)->Des(); |
|
310 |
|
311 // get the data from parent |
|
312 TInt err=iParent.Request(PMHelloMum, TIpcArgs(&pid, &env, &cwd)); |
|
313 |
|
314 DebugPrint(_L("Environment string: %S"), &env); |
|
315 DebugPrint(_L("Working directory: %S"), &cwd); |
|
316 |
|
317 if(err!=KErrNone) |
|
318 { |
|
319 DebugPrint(_L("I've become an orphan")); |
|
320 // release stuff |
|
321 iParent.Close(); |
|
322 User::Leave(err); |
|
323 break; |
|
324 } |
|
325 // apply to our process |
|
326 iEnv.ConstructL(reply().iVarCount,env); |
|
327 err=iFs.SetSessionPath(cwd); |
|
328 User::LeaveIfError(err); |
|
329 |
|
330 // free up the temporary descriptors |
|
331 CleanupStack::PopAndDestroy(2); |
|
332 |
|
333 // Attach the pipes! |
|
334 for (i=0; i<3; i++) |
|
335 { |
|
336 iFids.Attach(i, pipes[i]); |
|
337 if (pipes[i]!=0) |
|
338 CleanupStack::Pop(); |
|
339 } |
|
340 return; |
|
341 } |
|
342 DebugPrint(_L("Posix-%d is a top-level process"), pid()); |
|
343 User::LeaveIfError(PosixFilesystem::SetDefaultDir(iFs)); |
|
344 } |
|
345 |
|
346 int CPosixServer::POpen3(PosixParams* aParams, int& anErrno) |
|
347 { |
|
348 TInt err=KErrNoMemory; |
|
349 //coverity[alloc_fn] |
|
350 //coverity[assign] |
|
351 CPosixProcess* proc= new CPosixProcess(*this); |
|
352 if (proc!=0) |
|
353 { |
|
354 //coverity[leave_without_push] |
|
355 err=iFids.Reserve(aParams->pint); |
|
356 if (err==KErrNone) |
|
357 { |
|
358 TRAP(err,proc->POpen3L(aParams)); |
|
359 } |
|
360 if (err==KErrNone) |
|
361 { |
|
362 DebugPrint(_L("POpen3 created process %d"), proc->iPid); |
|
363 proc->iNextProcess=iChildren; |
|
364 iChildren=proc; |
|
365 return (int)proc->iPid; // success |
|
366 } |
|
367 delete proc; |
|
368 iFids.Detach(aParams->pint); |
|
369 } |
|
370 return MapError(err, anErrno); |
|
371 } |
|
372 |
|
373 CPosixRequest* CPosixServer::Waiters() |
|
374 { |
|
375 CPosixRequest* waiters=iWaitAnyQueue; |
|
376 iWaitAnyQueue=0; |
|
377 return waiters; |
|
378 } |
|
379 |
|
380 // CPosixSession |
|
381 // |
|
382 // Each local thread gets one of these |
|
383 |
|
384 CPosixSession::CPosixSession(CPosixServer& aServer) |
|
385 : iActive(aServer) |
|
386 { |
|
387 CActiveScheduler::Add(&iActive); |
|
388 __DECLARE_NAME(_S("CPosixSession")); |
|
389 } |
|
390 |
|
391 void CPosixSession::ServiceL(const RMessage2& aMessage) |
|
392 { |
|
393 iActive.Service(aMessage); |
|
394 } |
|
395 |
|
396 // CPosixRequest |
|
397 // |
|
398 // An active object contained within the Session that handles the deferred completion |
|
399 // of asynchronous functions (e.g. read & write). |
|
400 |
|
401 CPosixRequest::CPosixRequest(CPosixServer& aServer) |
|
402 : CActive(EPriorityStandard), iServer(aServer), iPtr(0,0) |
|
403 { |
|
404 // iFile=0; |
|
405 // iNewF=0; |
|
406 // iNewFid=0; |
|
407 } |
|
408 |
|
409 void CPosixRequest::Service(const RMessage2& aMessage) |
|
410 // |
|
411 // The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams |
|
412 // in p[1]. The result is written back into the PosixParams.retval field. |
|
413 // |
|
414 { |
|
415 if (aMessage.Function() == PMcancel) |
|
416 { |
|
417 Cancel(); // Cancel in the active scheduler |
|
418 if (iFile) |
|
419 EndAsynch(KErrCancel); // Complete the cancelled request & clean up |
|
420 aMessage.Complete(KErrNone); |
|
421 return; |
|
422 } |
|
423 |
|
424 if (iFile!=0) |
|
425 { |
|
426 aMessage.Complete(KErrInUse); |
|
427 return; |
|
428 } |
|
429 int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,aMessage.Ptr0())); |
|
430 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,aMessage.Ptr1())); |
|
431 switch (aMessage.Function()) |
|
432 { |
|
433 |
|
434 // Asynchronous functions need queuing, active objects etc. |
|
435 |
|
436 case PMread: |
|
437 case PMwrite: |
|
438 case PMsendto: |
|
439 case PMrecvfrom: |
|
440 iPtr.Set((TText8*)params->ptr[0], params->len[0], params->len[0]); |
|
441 // and fall through... |
|
442 case PMfsync: |
|
443 case PMconnect: |
|
444 case PMshutdown: |
|
445 { |
|
446 TInt err=Fids().Asynch(params->fid,iFile); |
|
447 if (!err) |
|
448 { |
|
449 QueueAsynch(aMessage); // start operation or queue if busy |
|
450 return; // deferred completion through RunL |
|
451 } |
|
452 params->ret=MapError(err,anErrno); |
|
453 } |
|
454 break; |
|
455 |
|
456 case PMaccept: |
|
457 { |
|
458 TInt err=Fids().Asynch(params->fid,iFile); |
|
459 if (!err) |
|
460 { |
|
461 iNewF=0; |
|
462 iNewFid=Fids().Reserve(); // reserve a fid for the accepted socket |
|
463 err=iNewFid; |
|
464 if (iNewFid>=0) |
|
465 { |
|
466 QueueAsynch(aMessage); // start operation or queue if busy |
|
467 return; // deferred completion through RunL |
|
468 } |
|
469 } |
|
470 params->ret=MapError(err,anErrno); |
|
471 } |
|
472 break; |
|
473 |
|
474 case PMioctl: |
|
475 case PMioctlN: |
|
476 { |
|
477 TInt err=Fids().Asynch(params->fid,iFile); |
|
478 if (!err) |
|
479 { |
|
480 QueueAsynch(aMessage); // start operation or queue if busy |
|
481 return; // deferred completion through RunL |
|
482 } |
|
483 |
|
484 aMessage.Complete(err); // Different calling convention |
|
485 return; |
|
486 } |
|
487 |
|
488 // complicated synchronous functions which might do their own completion |
|
489 |
|
490 case PMwaitpid: |
|
491 { |
|
492 // check for invalid options or if an invalid pid is specified. currently there is no |
|
493 // support for process group id's so a pid less than -1 or equal to 0 is invalid |
|
494 if((params->pint[1] & ~(WNOHANG|WUNTRACED))|| (params->pint[0] < -1) || (params->pint[0] ==0)) |
|
495 { |
|
496 anErrno=EINVAL; |
|
497 params->ret=-1; |
|
498 break; |
|
499 } |
|
500 if (params->pint[0]==-1 && params->pint[1]==0) /* wait for any child */ |
|
501 { |
|
502 iMessage=aMessage; |
|
503 iServer.WaitForAnyChild(this); |
|
504 return; // wait for the next child to die |
|
505 } |
|
506 CPosixProcess* child=iServer.Child(params->pint[0]); |
|
507 if (child!=0) |
|
508 { |
|
509 if (child->IsAlive()) |
|
510 { |
|
511 if (params->pint[1]&1) /* WNOHANG */ |
|
512 { |
|
513 params->ret=0; |
|
514 break; |
|
515 } |
|
516 iMessage=aMessage; |
|
517 child->Queue(this); |
|
518 return; // wait for the child to die |
|
519 } |
|
520 params->pint[0]=child->iExitReason; |
|
521 params->ret=child->iPid; |
|
522 iServer.Release(child); |
|
523 } |
|
524 else |
|
525 { |
|
526 anErrno=ECHILD; |
|
527 params->ret=-1; |
|
528 } |
|
529 } |
|
530 break; |
|
531 |
|
532 // simple synchronous functions |
|
533 |
|
534 case PMdup: |
|
535 params->ret=Fids().dup(params->fid,anErrno); |
|
536 break; |
|
537 case PMdup2: |
|
538 params->ret=Fids().dup2(params->fid,params->pint[0],anErrno); |
|
539 break; |
|
540 case PMopen: |
|
541 { |
|
542 const wchar_t* name = params->cwptr[0]; |
|
543 if ((L'C' == name[0]) && (L'O' == name[1]) && (L'M' == name[2]) && (L':' == name[4]) && ((name[3] >= L'1') && (name[3] <= L'9')) || |
|
544 (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'))) |
|
545 params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Cs()); |
|
546 else |
|
547 params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Fs()); |
|
548 |
|
549 } |
|
550 break; |
|
551 case PMclose: |
|
552 params->ret=Fids().userclose(params->fid,anErrno); |
|
553 break; |
|
554 case PMlseek: |
|
555 params->ret=Fids().lseek(params->fid,params->pint[0],params->pint[1],anErrno); |
|
556 break; |
|
557 case PMfstat: |
|
558 params->ret=Fids().fstat(params->fid,(struct stat*)params->ptr[0],anErrno); |
|
559 break; |
|
560 case PMgetcwd: |
|
561 // params->ret=(int)PosixFilesystem::getcwd(Fs(),params->ptr[0],params->len[0],anErrno); |
|
562 params->ret=(int)PosixFilesystem::getcwd(Fs(),params->wptr[0],params->len[0],anErrno); |
|
563 break; |
|
564 case PMchdir: |
|
565 params->ret=PosixFilesystem::chdir(Fs(),params->cwptr[0],anErrno); |
|
566 break; |
|
567 case PMmkdir: |
|
568 // params->ret=PosixFilesystem::mkdir(Fs(),params->cptr[0],params->pint[0],anErrno); |
|
569 params->ret=PosixFilesystem::mkdir(Fs(),params->cwptr[0],params->pint[0],anErrno); |
|
570 break; |
|
571 case PMrmdir: |
|
572 params->ret=PosixFilesystem::rmdir(Fs(),params->cwptr[0],anErrno); |
|
573 break; |
|
574 case PMchmod: |
|
575 params->ret=PosixFilesystem::chmod(Fs(),params->cwptr[0],params->pint[0],anErrno); |
|
576 break; |
|
577 case PMunlink: |
|
578 params->ret=PosixFilesystem::unlink(Fs(),params->cwptr[0],anErrno); |
|
579 break; |
|
580 case PMstat: |
|
581 params->ret=PosixFilesystem::stat(Fs(),params->cwptr[0],(struct stat*)params->ptr[0],anErrno); |
|
582 break; |
|
583 case PMrename: |
|
584 params->ret=PosixFilesystem::rename(Fs(), params->cwptr[0],params->cwptr[1],anErrno); |
|
585 break; |
|
586 case PMResolvePath: |
|
587 // params->ret=PosixFilesystem::ResolvePath(Fs(), |
|
588 // *(TParse*)params->ptr[0],params->cptr[0],(TDes*)params->ptr[1]); |
|
589 params->ret=PosixFilesystem::ResolvePath(Fs(), |
|
590 *(TParse*)params->ptr[0],params->cwptr[0],(TDes*)params->ptr[1]); |
|
591 break; |
|
592 case PMsocket: |
|
593 params->ret=Fids().socket(params->pint[0],params->pint[1],params->pint[2],anErrno,Ss()); |
|
594 break; |
|
595 case PMbind: |
|
596 params->ret=Fids().bind(params->fid,params->addr,anErrno); |
|
597 break; |
|
598 case PMlisten: |
|
599 params->ret=Fids().listen(params->fid,params->pint[0],anErrno); |
|
600 break; |
|
601 case PMsockname: |
|
602 params->ret=Fids().sockname(params->fid,params->addr,params->pint[0],anErrno); |
|
603 break; |
|
604 case PMgetsockopt: |
|
605 params->ret=Fids().getsockopt(params->fid,params->pint[0],params->pint[1], |
|
606 params->ptr[0],params->lenp[0],anErrno); |
|
607 break; |
|
608 case PMsetsockopt: |
|
609 params->ret=Fids().setsockopt(params->fid,params->pint[0],params->pint[1], |
|
610 params->ptr[0],params->len[0],anErrno); |
|
611 break; |
|
612 case PMgetenv: |
|
613 params->ret=(int)Env().getenv(params->cwptr[0]); |
|
614 break; |
|
615 case PMunsetenv: |
|
616 Env().unsetenv(params->cwptr[0]); // no return value |
|
617 break; |
|
618 case PMsetenv: |
|
619 params->ret=Env().setenv(params->cwptr[0],params->cwptr[1],params->pint[0],anErrno); |
|
620 break; |
|
621 case PMioctlcomplete: |
|
622 params->ret=Fids().ioctlcomplete(params->fid,params->pint[0],params->ptr[0],*(REINTERPRET_CAST(TRequestStatus*, params->ptr[1])), anErrno); |
|
623 break; |
|
624 case PMTerminateProcess: |
|
625 { |
|
626 int status = params->fid; |
|
627 RProcess().Kill(status); |
|
628 } |
|
629 break; |
|
630 case PMpopen3: |
|
631 params->ret=iServer.POpen3(params,anErrno); |
|
632 break; |
|
633 default: |
|
634 aMessage.Complete(KErrNotSupported); |
|
635 return; |
|
636 } |
|
637 // deal with completion of a synchronous request |
|
638 aMessage.Complete(KErrNone); |
|
639 } |
|
640 |
|
641 // Asynchronous requests |
|
642 // |
|
643 // 1. QueueAsynch() to get into the appropriate queue in the FileDesc |
|
644 // 2. FileDesc calls StartAsynch() when it's our turn |
|
645 // 3. StartAsynch() makes the relevant IO call and does SetActive() |
|
646 // 4a. RunL() handles the completion of the IO call and calls EndAsynch() |
|
647 // 4b. DoCancel() handles cancellation of the IO call, but doesn't call EndAsynch() |
|
648 // 5. EndAsynch() removes us from the FileDesc queue and completes iMessage |
|
649 // |
|
650 |
|
651 void CPosixRequest::QueueAsynch(const RMessage2& aMessage) |
|
652 // |
|
653 // Add this to the appropriate queue in the associated file |
|
654 // |
|
655 { |
|
656 iMessage=aMessage; // Suggested by AndrewT to avoid code duplication |
|
657 iQueue=CFileDescBase::IOwriteQ; |
|
658 switch (aMessage.Function()) |
|
659 { |
|
660 case PMread: |
|
661 case PMrecvfrom: |
|
662 iQueue=CFileDescBase::IOreadQ; |
|
663 break; |
|
664 case PMioctl: |
|
665 iQueue=CFileDescBase::IOioctlQ; |
|
666 break; |
|
667 case PMioctlN: |
|
668 iQueue=CFileDescBase::IOioctlNQ; |
|
669 break; |
|
670 default: |
|
671 // everything else uses the IOwriteQ, including Accept and Connect |
|
672 break; |
|
673 } |
|
674 |
|
675 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO)); |
|
676 iFile->AddLast(*this,iQueue); |
|
677 } |
|
678 |
|
679 void CPosixRequest::StartAsynch() |
|
680 // |
|
681 // The request has reached the front of the queue and can now be actioned |
|
682 // |
|
683 { |
|
684 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1())); |
|
685 switch (iMessage.Function()) |
|
686 { |
|
687 case PMread: |
|
688 { |
|
689 |
|
690 //if we need to have a timer for this operation to cancel it later |
|
691 if (iFile->TimedRead()) |
|
692 { |
|
693 iFile->ReadIsTimed = ETrue; |
|
694 TRAPD(tRes, {iFile->TimedMessage = CSerialTimer::NewL(iFile);}); |
|
695 if (tRes != KErrNone) |
|
696 { |
|
697 //we have a problem here |
|
698 //basically, fake the async request completing with the returned error |
|
699 iStatus = KRequestPending; |
|
700 SetActive(); |
|
701 TRequestStatus * ps = &iStatus; |
|
702 User::RequestComplete(ps, tRes); |
|
703 return; |
|
704 } |
|
705 |
|
706 iFile->TimedMessage->IssueRequest(); |
|
707 } |
|
708 else |
|
709 iFile->ReadIsTimed = EFalse; |
|
710 |
|
711 iFile->ReadWasCancelled = EFalse; |
|
712 |
|
713 iFile->Read(iPtr,iStatus); |
|
714 |
|
715 } |
|
716 break; |
|
717 case PMrecvfrom: |
|
718 iFile->RecvFrom(iPtr,params->addr,params->pint[0],iStatus); |
|
719 break; |
|
720 case PMwrite: |
|
721 iFile->Write(iPtr,iStatus); |
|
722 break; |
|
723 case PMsendto: |
|
724 iFile->SendTo(iPtr,params->addr,params->pint[0],iStatus); |
|
725 break; |
|
726 case PMfsync: |
|
727 iFile->Sync(iStatus); |
|
728 break; |
|
729 case PMconnect: |
|
730 iFile->Connect(params->addr,iStatus); |
|
731 break; |
|
732 case PMshutdown: |
|
733 iFile->Shutdown(params->pint[0],iStatus); |
|
734 break; |
|
735 case PMaccept: |
|
736 iFile->Accept(iNewF,iStatus,Ss()); |
|
737 break; |
|
738 case PMioctl: |
|
739 iFile->Ioctl(params->pint[0],params->ptr[0],iStatus); |
|
740 break; |
|
741 case PMioctlN: |
|
742 iFile->Ioctl(params->pint[0],params->ptr[0],iStatus); |
|
743 break; |
|
744 default: |
|
745 EndAsynch(KErrGeneral); |
|
746 return; |
|
747 } |
|
748 SetActive(); // for asynchronous completion via RunL |
|
749 return; |
|
750 } |
|
751 |
|
752 void CPosixRequest::RunL() |
|
753 // |
|
754 // The pending IO has completed, so handle the result |
|
755 // |
|
756 { |
|
757 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO)); |
|
758 TInt completion=KErrNone; |
|
759 int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,iMessage.Ptr0())); |
|
760 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1())); |
|
761 switch (iMessage.Function()) |
|
762 { |
|
763 case PMread: |
|
764 { |
|
765 if (iFile->ReadIsTimed) |
|
766 { |
|
767 //need to stop the timer |
|
768 delete iFile->TimedMessage; |
|
769 iFile->TimedMessage = NULL; |
|
770 iFile->ReadIsTimed = EFalse; |
|
771 } |
|
772 |
|
773 TInt err=iFile->ReadCompletion(iPtr, iStatus.Int()); |
|
774 if (err==0) |
|
775 { |
|
776 params->ret=iPtr.Length(); |
|
777 break; |
|
778 } |
|
779 //if the read was cancelled and we are to patch it due to me cancelling it |
|
780 |
|
781 if (iFile->ReadWasCancelled) |
|
782 { |
|
783 err = ETIMEDOUT; |
|
784 iFile->ReadWasCancelled = EFalse; |
|
785 } |
|
786 |
|
787 params->ret=MapError(err,anErrno); |
|
788 } |
|
789 break; |
|
790 case PMwrite: |
|
791 { |
|
792 TInt err=iFile->WriteCompletion(iPtr, iStatus.Int()); |
|
793 if (err==0) |
|
794 { |
|
795 params->ret=iPtr.Length(); |
|
796 break; |
|
797 } |
|
798 params->ret=MapError(err,anErrno); |
|
799 } |
|
800 break; |
|
801 case PMconnect: |
|
802 case PMshutdown: |
|
803 case PMfsync: |
|
804 params->ret=MapError(iStatus.Int(),anErrno); |
|
805 break; |
|
806 case PMsendto: |
|
807 { |
|
808 TInt err=iFile->SendToCompletion(iPtr, iStatus.Int()); |
|
809 if (err==0) |
|
810 { |
|
811 params->ret=iPtr.Length(); |
|
812 break; |
|
813 } |
|
814 params->ret=MapError(err,anErrno); |
|
815 } |
|
816 break; |
|
817 case PMrecvfrom: |
|
818 { |
|
819 TInt err=iFile->RecvFromCompletion(params->ret, iStatus.Int()); |
|
820 if (err==0) |
|
821 { |
|
822 params->ret=iPtr.Length(); |
|
823 break; |
|
824 } |
|
825 params->ret=MapError(err,anErrno); |
|
826 } |
|
827 break; |
|
828 case PMaccept: |
|
829 { |
|
830 TInt err=iStatus.Int(); |
|
831 if (err) |
|
832 Fids().Attach(iNewFid,0); // cancel the reservation |
|
833 else |
|
834 { |
|
835 err=Fids().Attach(iNewFid,iNewF); |
|
836 if (!err) |
|
837 { |
|
838 params->ret=iNewFid; |
|
839 break; // so that we return the new fid |
|
840 } |
|
841 delete iNewF; |
|
842 iNewF=0; |
|
843 } |
|
844 params->ret=MapError(err,anErrno); |
|
845 } |
|
846 break; |
|
847 |
|
848 case PMioctlN: |
|
849 { |
|
850 completion=iStatus.Int(); // caller picks up completion explicitly |
|
851 } |
|
852 break; |
|
853 |
|
854 case PMioctl: |
|
855 { |
|
856 completion=iStatus.Int(); // caller picks up completion explicitly |
|
857 // TInt err=iFile->IoctlCompletion(params->pint[0], ¶ms->ret, iStatus.Int()); |
|
858 // params->ret=MapError(err,anErrno); |
|
859 } |
|
860 break; |
|
861 |
|
862 default: |
|
863 completion=KErrGeneral; // arrgh - I imagine that it's going to die if we get here... |
|
864 break; |
|
865 } |
|
866 EndAsynch(completion); |
|
867 } |
|
868 |
|
869 void CPosixRequest::EndAsynch(TInt aResult) |
|
870 // |
|
871 // finish an asynchronous operation and complete iMessage |
|
872 // |
|
873 { |
|
874 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO)); |
|
875 iFile->Remove(*this,iQueue); |
|
876 iFile->Close(); // balances the Dup() in CFileTable::Asynch(), may delete object! |
|
877 iFile=0; |
|
878 iMessage.Complete(aResult); |
|
879 } |
|
880 |
|
881 |
|
882 void CPosixRequest::DoCancel() |
|
883 // |
|
884 // The pending IO has been cancelled, so cancel the outstanding request |
|
885 // Needs to deal with all of the cases in RunL, but doesn't call EndAsynch(). |
|
886 // This is called from CActive::Cancel() only when the object is active, but |
|
887 // EndAsynch() needs to be called when the object is active or when it's just |
|
888 // waiting in a FileDesc queue. |
|
889 // |
|
890 { |
|
891 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO)); |
|
892 switch (iMessage.Function()) |
|
893 { |
|
894 case PMread: |
|
895 iFile->ReadCancel(); |
|
896 break; |
|
897 case PMrecvfrom: |
|
898 iFile->RecvFromCancel(); |
|
899 break; |
|
900 case PMwrite: |
|
901 iFile->WriteCancel(); |
|
902 break; |
|
903 case PMsendto: |
|
904 iFile->SendToCancel(); |
|
905 break; |
|
906 case PMfsync: |
|
907 iFile->SyncCancel(); |
|
908 break; |
|
909 case PMconnect: |
|
910 iFile->ConnectCancel(); |
|
911 break; |
|
912 case PMshutdown: |
|
913 iFile->ShutdownCancel(); |
|
914 break; |
|
915 case PMaccept: |
|
916 iFile->AcceptCancel(); |
|
917 Fids().Attach(iNewFid,0); // cancel the reservation |
|
918 break; |
|
919 case PMioctl: |
|
920 iFile->IoctlCancel(); |
|
921 break; |
|
922 default: |
|
923 // it would be wrong to get here, so leave well alone |
|
924 break; |
|
925 } |
|
926 } |
|
927 |
|
928 CPosixRequest::~CPosixRequest() |
|
929 { |
|
930 Cancel(); |
|
931 if (iFile) |
|
932 EndAsynch(KErrCancel); |
|
933 } |
|
934 |
|
935 // Handling waiting on other processes |
|
936 // |
|
937 void CPosixRequest::EnList(CPosixRequest*& aHead) |
|
938 { |
|
939 iNext=aHead; |
|
940 aHead=this; |
|
941 } |
|
942 |
|
943 void CPosixRequest::WaitCompleted(TInt aPid, TInt aReason) |
|
944 { |
|
945 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1())); |
|
946 |
|
947 __ASSERT_DEBUG(iMessage.Function()==PMwaitpid, CPosixServer::ServerPanic(EPosix_BadWaitCompletion)); |
|
948 params->pint[0]=aReason; |
|
949 params->ret=aPid; |
|
950 iMessage.Complete(KErrNone); |
|
951 |
|
952 CPosixRequest* next=iNext; |
|
953 iNext=0; |
|
954 if (next) |
|
955 next->WaitCompleted(aPid, aReason); |
|
956 } |
|
957 |
|
958 static void ClosePipes(CPipeDesc* aPipes[3]) |
|
959 { |
|
960 TInt i=0; |
|
961 for (i=0; i<3; i++) |
|
962 { |
|
963 CPipeDesc* pipe=aPipes[i]; |
|
964 aPipes[i]=0; |
|
965 if (pipe) |
|
966 pipe->ClientClose(); |
|
967 } |
|
968 } |
|
969 |
|
970 TInt CPosixIPCSession::AreYouMyMotherL(const RMessage2& aMessage) |
|
971 { |
|
972 TPosixIPCPid pid; |
|
973 TPosixIPCReply reply; |
|
974 aMessage.ReadL(0,pid); |
|
975 DebugPrint(_L("Process %d asks am I its mother?"), pid()); |
|
976 CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server())); |
|
977 CPosixProcess* child=pServ->Child(pid()); |
|
978 if (!child) |
|
979 return KErrNotFound; // you are no child of mine |
|
980 DebugPrint(_L("Found child process")); |
|
981 child->Sizes(reply); |
|
982 aMessage.Write(1,reply); |
|
983 return KErrNone; |
|
984 } |
|
985 |
|
986 TInt CPosixIPCSession::HelloMumL(const RMessage2& aMessage) |
|
987 { |
|
988 TPosixIPCPid pid; |
|
989 aMessage.ReadL(0,pid); |
|
990 |
|
991 DebugPrint(_L("Process %d is requesting its inheritance"),pid()); |
|
992 |
|
993 CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server())); |
|
994 CPosixProcess* child=pServ->Child(pid()); |
|
995 if (!child) |
|
996 return KErrNotFound; // you are no child of mine |
|
997 |
|
998 // CopyToChildL will pull out the second and third element out directly so as |
|
999 // to copy data to it. This is why data is passed in this way. |
|
1000 child->CopyToChildL(aMessage); |
|
1001 return KErrNone; |
|
1002 } |
|
1003 |
|
1004 void CPosixIPCSession::PipeRead(const RMessage2& aMessage) |
|
1005 { |
|
1006 TInt index=aMessage.Int0(); |
|
1007 if (iPipes[index]==0) |
|
1008 aMessage.Complete(KErrEof); // go away, incorrect thing! |
|
1009 else |
|
1010 iPipes[index]->ClientRead(aMessage); |
|
1011 } |
|
1012 |
|
1013 void CPosixIPCSession::PipeWrite(const RMessage2& aMessage) |
|
1014 { |
|
1015 TInt index=aMessage.Int0(); |
|
1016 if (iPipes[index]==0) |
|
1017 aMessage.Complete(KErrEof); // go away, incorrect thing! |
|
1018 else |
|
1019 iPipes[index]->ClientWrite(aMessage); |
|
1020 } |
|
1021 |
|
1022 void CPosixIPCSession::PipeIoctl(const RMessage2& aMessage) |
|
1023 { |
|
1024 TInt index=aMessage.Int0(); |
|
1025 if (iPipes[index]==0) |
|
1026 aMessage.Complete(KErrEof); // go away, incorrect thing! |
|
1027 else |
|
1028 iPipes[index]->ClientIoctl(aMessage); |
|
1029 } |
|
1030 |
|
1031 void CPosixIPCSession::PipeClose(const RMessage2& aMessage) |
|
1032 { |
|
1033 TInt index=aMessage.Int0(); |
|
1034 if (iPipes[index]!=0) |
|
1035 iPipes[index]->ClientClose(); |
|
1036 aMessage.Complete(KErrNone); |
|
1037 } |
|
1038 |
|
1039 void CPosixIPCSession::PipeCancel(const RMessage2& aMessage) |
|
1040 { |
|
1041 TInt index=aMessage.Int0(); |
|
1042 if (iPipes[index]!=0) |
|
1043 iPipes[index]->ClientCancel(aMessage); |
|
1044 aMessage.Complete(KErrNone); |
|
1045 } |
|
1046 |
|
1047 void CPosixIPCSession::ServiceL(const RMessage2& aMessage) |
|
1048 // |
|
1049 // Handle the communication between CPosixServers |
|
1050 // |
|
1051 { |
|
1052 TInt response=KErrNone; |
|
1053 switch (aMessage.Function()) |
|
1054 { |
|
1055 case PMAreYouMyMother: |
|
1056 response=AreYouMyMotherL(aMessage); |
|
1057 break; |
|
1058 case PMHelloMum: |
|
1059 response=HelloMumL(aMessage); |
|
1060 break; |
|
1061 |
|
1062 case PMPipeRead: |
|
1063 PipeRead(aMessage); |
|
1064 return; // handles completion |
|
1065 case PMPipeWrite: |
|
1066 PipeWrite(aMessage); |
|
1067 return; // handles completion |
|
1068 case PMPipeIoctl: |
|
1069 PipeIoctl(aMessage); |
|
1070 return; // handles completion |
|
1071 case PMPipeClose: |
|
1072 PipeClose(aMessage); |
|
1073 return; // handles completion |
|
1074 |
|
1075 case PMPipeCancel: |
|
1076 PipeCancel(aMessage); |
|
1077 return; |
|
1078 |
|
1079 default: |
|
1080 response=KErrNotSupported; |
|
1081 break; |
|
1082 } |
|
1083 aMessage.Complete(response); |
|
1084 } |
|
1085 |
|
1086 void CPosixIPCSession::SetPipes(CPipeDesc* aPipes[3]) |
|
1087 // |
|
1088 // Accept ownership of the pipes between child and parent |
|
1089 // |
|
1090 { |
|
1091 TInt i=0; |
|
1092 for (i=0; i<3; i++) |
|
1093 { |
|
1094 CPipeDesc* pipe=aPipes[i]; |
|
1095 iPipes[i]=pipe; |
|
1096 aPipes[i]=0; |
|
1097 if (pipe) |
|
1098 pipe->SetClientSide(iPipes[i]); |
|
1099 } |
|
1100 } |
|
1101 |
|
1102 CPosixIPCSession::~CPosixIPCSession() |
|
1103 { |
|
1104 ClosePipes(iPipes); |
|
1105 } |
|
1106 |
|
1107 // Active Object representing a POSIX process |
|
1108 |
|
1109 CPosixProcess::CPosixProcess(CPosixServer& aServer) |
|
1110 : CActive(EPriorityStandard), iServer(aServer) |
|
1111 { |
|
1112 // iPid=0; |
|
1113 // iWaiters=0; |
|
1114 // iNextProcess=0; |
|
1115 // iEnvironment=0; |
|
1116 // iWorkingDirectory=0; |
|
1117 } |
|
1118 |
|
1119 CPosixProcess* CPosixProcess::Find(CPosixProcess* proc, TInt pid) |
|
1120 { |
|
1121 while (proc!=0) |
|
1122 { |
|
1123 if (proc->iPid==pid) |
|
1124 return proc; |
|
1125 if (pid==-1 && !proc->IsAlive()) // for waitpid(WAIT_ANY,...) |
|
1126 return proc; |
|
1127 proc=proc->iNextProcess; |
|
1128 } |
|
1129 return 0; |
|
1130 } |
|
1131 |
|
1132 void CPosixProcess::Release(CPosixProcess** aHead, CPosixProcess* aChild) |
|
1133 { |
|
1134 while (*aHead!=0) |
|
1135 { |
|
1136 if ((*aHead)==aChild) |
|
1137 { |
|
1138 (*aHead)=aChild->iNextProcess; |
|
1139 aChild->iNextProcess=0; |
|
1140 delete aChild; |
|
1141 return; |
|
1142 } |
|
1143 aHead=&(*aHead)->iNextProcess; |
|
1144 } |
|
1145 } |
|
1146 |
|
1147 |
|
1148 |
|
1149 void CPosixProcess::POpen3L(PosixParams* aParams) |
|
1150 { |
|
1151 TInt i=0; |
|
1152 CPipeDesc* pipes[3]; |
|
1153 for (i=0; i<3; i++) |
|
1154 { |
|
1155 if (aParams->pint[i]<0) |
|
1156 pipes[i]=0; |
|
1157 else |
|
1158 { |
|
1159 pipes[i]=new(ELeave) CPipeDesc(i); |
|
1160 pipes[i]->PushLC(); |
|
1161 } |
|
1162 } |
|
1163 // truncate fileName to get the name of the executable |
|
1164 TPtrC16 fileName((TText16*)aParams->wptr[0]); |
|
1165 TPtrC16 commandLine((TText16*)aParams->cwptr[0]); |
|
1166 |
|
1167 HBufC16* env=Env().ExternalizeLC(iVarCount,aParams->eptr[0]); |
|
1168 TFullName workingDirectory; |
|
1169 TInt err=Fs().SessionPath(workingDirectory); |
|
1170 User::LeaveIfError(err); |
|
1171 HBufC* cwd=workingDirectory.AllocLC(); |
|
1172 |
|
1173 // Use real processes |
|
1174 err=iChild.Create(fileName,commandLine,EOwnerThread); |
|
1175 User::LeaveIfError(err); |
|
1176 TProcessId id=iChild.Id(); |
|
1177 iPid=*REINTERPRET_CAST(int*,&id); |
|
1178 iChild.Logon(iStatus); |
|
1179 CActiveScheduler::Add(this); |
|
1180 SetActive(); |
|
1181 iChild.Resume(); |
|
1182 iEnvironment=env; |
|
1183 iWorkingDirectory=cwd; |
|
1184 CleanupStack::Pop(2); |
|
1185 // Sort out the pipes |
|
1186 for (i=0; i<3; i++) |
|
1187 { |
|
1188 CPipeDesc* pipe=pipes[i]; |
|
1189 iPipes[i]=pipe; |
|
1190 if (pipe!=0) |
|
1191 { |
|
1192 CleanupStack::Pop(); |
|
1193 Fids().Attach(aParams->pint[i],pipe); |
|
1194 pipe->SetClientSide(iPipes[i]); // for FinalClose |
|
1195 } |
|
1196 } |
|
1197 } |
|
1198 |
|
1199 void CPosixProcess::Sizes(TPosixIPCReply& aReply) const |
|
1200 { |
|
1201 aReply().iWorkingDirectorySize=iWorkingDirectory->Length(); |
|
1202 aReply().iEnvironmentSize=iEnvironment->Length(); |
|
1203 aReply().iVarCount=iVarCount; |
|
1204 TUint mask=0; |
|
1205 TInt i=0; |
|
1206 for (i=0; i<3; i++) |
|
1207 { |
|
1208 if (iPipes[i]!=0) |
|
1209 mask |= 1<<i; |
|
1210 } |
|
1211 aReply().iPipeMask=mask; |
|
1212 } |
|
1213 |
|
1214 void CPosixProcess::CopyToChildL(const RMessage2& aMessage) |
|
1215 { |
|
1216 // copy iWorkingDirectory and iEnvironment to params |
|
1217 aMessage.WriteL(1, *iEnvironment); |
|
1218 aMessage.WriteL(2, *iWorkingDirectory); |
|
1219 |
|
1220 // don't need this data anymore |
|
1221 delete iWorkingDirectory; |
|
1222 iWorkingDirectory=0; |
|
1223 delete iEnvironment; |
|
1224 iEnvironment=0; |
|
1225 |
|
1226 (static_cast<CPosixIPCSession*>(aMessage.Session()))->SetPipes(iPipes); |
|
1227 } |
|
1228 |
|
1229 void CPosixProcess::RunL() |
|
1230 // |
|
1231 // Detects termination of the child process |
|
1232 // |
|
1233 { |
|
1234 iExitReason=iStatus.Int(); |
|
1235 iChild.Close(); |
|
1236 DebugPrint(_L("Process %d appears to have terminated with status %d"), iPid, iExitReason); |
|
1237 ClosePipes(iPipes); |
|
1238 |
|
1239 TInt reported=0; |
|
1240 CPosixRequest* waiters=iWaiters; |
|
1241 iWaiters=0; |
|
1242 if (waiters) |
|
1243 { |
|
1244 waiters->WaitCompleted(iPid,iExitReason); |
|
1245 reported=1; |
|
1246 } |
|
1247 |
|
1248 // And any of the outstanding "wait for any" requests held in the server |
|
1249 waiters=iServer.Waiters(); |
|
1250 if (waiters) |
|
1251 { |
|
1252 waiters->WaitCompleted(iPid,iExitReason); |
|
1253 reported=1; |
|
1254 } |
|
1255 if (reported) |
|
1256 iServer.Release(this); |
|
1257 } |
|
1258 |
|
1259 void CPosixProcess::DoCancel() |
|
1260 { |
|
1261 // panic if iNextProcess or iWaiters is non-zero? |
|
1262 iChild.LogonCancel(iStatus); |
|
1263 iChild.Close(); |
|
1264 delete iEnvironment; |
|
1265 iEnvironment=0; |
|
1266 delete iWorkingDirectory; |
|
1267 iWorkingDirectory=0; |
|
1268 ClosePipes(iPipes); |
|
1269 } |
|
1270 |
|
1271 CPosixProcess::~CPosixProcess() |
|
1272 { |
|
1273 Cancel(); |
|
1274 } |
|
1275 |
|
1276 // System Interface for process form of STDLIB |
|
1277 |
|
1278 CProcessSystemInterface::CProcessSystemInterface() |
|
1279 {} |
|
1280 |
|
1281 CProcessSystemInterface::~CProcessSystemInterface() |
|
1282 { |
|
1283 iSession.Close(); |
|
1284 } |
|
1285 |
|
1286 MSystemInterface& CProcessSystemInterface::Clone() |
|
1287 { |
|
1288 return *(new CProcessSystemInterface); |
|
1289 } |
|
1290 |
|
1291 void CProcessSystemInterface::Release() |
|
1292 { |
|
1293 delete this; |
|
1294 } |
|
1295 |
|
1296 TInt CProcessSystemInterface::Connect() |
|
1297 { |
|
1298 return iSession.Connect(); // is this the right thread though? |
|
1299 } |
|
1300 |
|
1301 // CProcessSystemInterface functions |
|
1302 // |
|
1303 // These functions just package up their arguments for transmission to the |
|
1304 // CPosixServer which will unpack them and call the corresponding function in |
|
1305 // its associated CLocalSystemInterface, except for the asynchronous functions |
|
1306 // (currently read/write/fsync) which the server handles separately using an active |
|
1307 // object to defer the RMessage::Complete until the asynchronous operation has completed. |
|
1308 |
|
1309 static void doPanic(TInt aFunction, TInt aErr) |
|
1310 { |
|
1311 TBuf<100> detail; |
|
1312 _LIT(KProcessSystemInterfacePanic, "POSIXIF (%d)"); |
|
1313 detail.Format(KProcessSystemInterfacePanic, aFunction); |
|
1314 User::Panic(detail,aErr); |
|
1315 } |
|
1316 |
|
1317 int CProcessSystemInterface::Request (TInt aFunction, int& anErrno) |
|
1318 { |
|
1319 TInt err=iSession.Request(aFunction,anErrno,iParams); |
|
1320 // KErrServerTerminated? |
|
1321 if (err!=KErrNone) |
|
1322 doPanic(aFunction,err); // moved out of line to reduce stack requirement |
|
1323 return iParams.ret; |
|
1324 } |
|
1325 |
|
1326 void CProcessSystemInterface::Request (TInt aFunction, int& anErrno, TRequestStatus& aStatus) |
|
1327 { |
|
1328 iSession.Request(aFunction,anErrno,iParams,aStatus); |
|
1329 } |
|
1330 |
|
1331 void CProcessSystemInterface::TerminateProcess (int status) |
|
1332 { |
|
1333 int anErrno; |
|
1334 iParams.fid=status; |
|
1335 Request(PMTerminateProcess,anErrno); |
|
1336 RProcess().Terminate(status); // just in case... |
|
1337 } |
|
1338 |
|
1339 int CProcessSystemInterface::dup (int fid, int& anErrno) |
|
1340 { |
|
1341 iParams.fid=fid; |
|
1342 return Request(PMdup,anErrno); |
|
1343 } |
|
1344 |
|
1345 int CProcessSystemInterface::dup2 (int fid, int fid2, int& anErrno) |
|
1346 { |
|
1347 iParams.fid=fid; |
|
1348 iParams.pint[0]=fid2; |
|
1349 return Request(PMdup2,anErrno); |
|
1350 } |
|
1351 |
|
1352 int CProcessSystemInterface::open (const wchar_t* name, int mode, int perms, int& anErrno) |
|
1353 { |
|
1354 iParams.cwptr[0]=name; |
|
1355 iParams.pint[0]=mode; |
|
1356 iParams.pint[1]=perms; |
|
1357 return Request(PMopen,anErrno); |
|
1358 } |
|
1359 |
|
1360 int CProcessSystemInterface::read (int fid, char* buf, unsigned long len, int& anErrno) |
|
1361 { |
|
1362 iParams.fid=fid; |
|
1363 iParams.ptr[0]=buf; |
|
1364 iParams.len[0]=len; |
|
1365 return Request(PMread,anErrno); |
|
1366 } |
|
1367 |
|
1368 int CProcessSystemInterface::write (int fid, const char* buf, unsigned long len, int& anErrno) |
|
1369 { |
|
1370 iParams.fid=fid; |
|
1371 iParams.ptr[0]=CONST_CAST(char*,buf); |
|
1372 iParams.len[0]=len; |
|
1373 return Request(PMwrite,anErrno); |
|
1374 } |
|
1375 |
|
1376 int CProcessSystemInterface::fsync (int fid, int& anErrno) |
|
1377 { |
|
1378 iParams.fid=fid; |
|
1379 return Request(PMfsync,anErrno); |
|
1380 } |
|
1381 |
|
1382 int CProcessSystemInterface::close (int fid, int& anErrno) |
|
1383 { |
|
1384 iParams.fid=fid; |
|
1385 return Request(PMclose,anErrno); |
|
1386 } |
|
1387 |
|
1388 int CProcessSystemInterface::lseek (int fid, int offset, int whence, int& anErrno) |
|
1389 { |
|
1390 iParams.fid=fid; |
|
1391 iParams.pint[0]=offset; |
|
1392 iParams.pint[1]=whence; |
|
1393 return Request(PMlseek,anErrno); |
|
1394 } |
|
1395 |
|
1396 int CProcessSystemInterface::fstat (int fid, struct stat *st, int& anErrno) |
|
1397 { |
|
1398 iParams.fid=fid; |
|
1399 iParams.ptr[0]=(char*)st; |
|
1400 return Request(PMfstat,anErrno); |
|
1401 } |
|
1402 |
|
1403 |
|
1404 wchar_t * CProcessSystemInterface::getcwd (wchar_t* buf, unsigned long len, int& anErrno) |
|
1405 { |
|
1406 iParams.wptr[0]=buf; |
|
1407 |
|
1408 iParams.len[0]=len; |
|
1409 return (wchar_t *)Request(PMgetcwd,anErrno); |
|
1410 } |
|
1411 |
|
1412 |
|
1413 int CProcessSystemInterface::chdir (const wchar_t* aPath, int& anErrno) |
|
1414 { |
|
1415 iParams.cwptr[0]=aPath; |
|
1416 return Request(PMchdir,anErrno); |
|
1417 } |
|
1418 |
|
1419 int CProcessSystemInterface::mkdir (const wchar_t* aPath, int perms, int& anErrno) |
|
1420 { |
|
1421 iParams.cwptr[0]=aPath; |
|
1422 iParams.pint[0]=perms; |
|
1423 return Request(PMmkdir,anErrno); |
|
1424 } |
|
1425 |
|
1426 int CProcessSystemInterface::rmdir (const wchar_t* aPath, int& anErrno) |
|
1427 { |
|
1428 iParams.cwptr[0]=aPath; |
|
1429 return Request(PMrmdir,anErrno); |
|
1430 } |
|
1431 |
|
1432 int CProcessSystemInterface::stat (const wchar_t* name, struct stat *st, int& anErrno) |
|
1433 { |
|
1434 iParams.cwptr[0]=name; |
|
1435 iParams.ptr[0]=(char*)st; |
|
1436 return Request(PMstat,anErrno); |
|
1437 } |
|
1438 |
|
1439 int CProcessSystemInterface::chmod (const wchar_t* name, int perms, int& anErrno) |
|
1440 { |
|
1441 iParams.cwptr[0]=name; |
|
1442 iParams.pint[0]=perms; |
|
1443 return Request(PMchmod,anErrno); |
|
1444 } |
|
1445 |
|
1446 int CProcessSystemInterface::unlink (const wchar_t* name, int& anErrno) |
|
1447 { |
|
1448 iParams.cwptr[0]=name; |
|
1449 return Request(PMunlink,anErrno); |
|
1450 } |
|
1451 |
|
1452 int CProcessSystemInterface::rename (const wchar_t* oldname, const wchar_t* newname, int& anErrno) |
|
1453 { |
|
1454 iParams.cwptr[0]=oldname; |
|
1455 iParams.cwptr[1]=newname; |
|
1456 return Request(PMrename,anErrno); |
|
1457 } |
|
1458 |
|
1459 TInt CProcessSystemInterface::ResolvePath (TParse& aResult, const wchar_t* path, TDes* aFilename) |
|
1460 { |
|
1461 TInt ignored; |
|
1462 iParams.ptr[0]=(char*)&aResult; |
|
1463 iParams.cwptr[0]=path; |
|
1464 iParams.ptr[1]=(char*)aFilename; |
|
1465 return Request(PMResolvePath,ignored); |
|
1466 } |
|
1467 |
|
1468 TInt CProcessSystemInterface::socket (int family, int style, int protocol, int& anErrno) |
|
1469 { |
|
1470 iParams.pint[0]=family; |
|
1471 iParams.pint[1]=style; |
|
1472 iParams.pint[2]=protocol; |
|
1473 return Request(PMsocket,anErrno); |
|
1474 } |
|
1475 |
|
1476 TInt CProcessSystemInterface::shutdown (int fid, int how, int& anErrno) |
|
1477 { |
|
1478 iParams.fid=fid; |
|
1479 iParams.pint[0]=how; |
|
1480 return Request(PMshutdown,anErrno); |
|
1481 } |
|
1482 |
|
1483 TInt CProcessSystemInterface::listen (int fid, int n, int& anErrno) |
|
1484 { |
|
1485 iParams.fid=fid; |
|
1486 iParams.pint[0]=n; |
|
1487 return Request(PMlisten,anErrno); |
|
1488 } |
|
1489 |
|
1490 TInt CProcessSystemInterface::accept (int fid, int& anErrno) |
|
1491 { |
|
1492 iParams.fid=fid; |
|
1493 return Request(PMaccept,anErrno); |
|
1494 } |
|
1495 |
|
1496 TInt CProcessSystemInterface::bind (int fid, struct sockaddr* addr, unsigned long size, int& anErrno) |
|
1497 { |
|
1498 iParams.fid=fid; |
|
1499 iParams.addr.Set(addr, size); |
|
1500 return Request(PMbind,anErrno); |
|
1501 } |
|
1502 |
|
1503 TInt CProcessSystemInterface::connect (int fid, struct sockaddr* addr, unsigned long size, int& anErrno) |
|
1504 { |
|
1505 iParams.fid=fid; |
|
1506 iParams.addr.Set(addr, size); |
|
1507 return Request(PMconnect,anErrno); |
|
1508 } |
|
1509 |
|
1510 TInt CProcessSystemInterface::recvfrom (int fid, char* buf, unsigned long len, int flags, struct sockaddr* from, unsigned long* fromsize, int& anErrno) |
|
1511 { |
|
1512 iParams.fid=fid; |
|
1513 iParams.ptr[0]=buf; |
|
1514 iParams.len[0]=len; |
|
1515 iParams.pint[0]=flags; |
|
1516 iParams.addr.Prepare(from); |
|
1517 TInt nbytes=Request(PMrecvfrom,anErrno); |
|
1518 if (nbytes>=0) // i.e. no error |
|
1519 iParams.addr.Get(from,fromsize); |
|
1520 return nbytes; |
|
1521 } |
|
1522 |
|
1523 TInt CProcessSystemInterface::sendto (int fid, const char* buf, unsigned long len, int flags, struct sockaddr* to, unsigned long tosize, int& anErrno) |
|
1524 { |
|
1525 iParams.fid=fid; |
|
1526 iParams.ptr[0]=CONST_CAST(char*,buf); |
|
1527 iParams.len[0]=len; |
|
1528 iParams.pint[0]=flags; |
|
1529 iParams.addr.Set(to,tosize); |
|
1530 return Request(PMsendto,anErrno); |
|
1531 } |
|
1532 |
|
1533 TInt CProcessSystemInterface::getsockopt (int fid, int level, int opt, void* buf, unsigned long* len, int& anErrno) |
|
1534 { |
|
1535 iParams.fid=fid; |
|
1536 iParams.pint[0]=level; |
|
1537 iParams.pint[1]=opt; |
|
1538 iParams.ptr[0]=(char*)buf; |
|
1539 iParams.lenp[0]=len; |
|
1540 return Request(PMgetsockopt,anErrno); |
|
1541 } |
|
1542 |
|
1543 TInt CProcessSystemInterface::setsockopt (int fid, int level, int opt, void* buf, unsigned long len, int& anErrno) |
|
1544 { |
|
1545 iParams.fid=fid; |
|
1546 iParams.pint[0]=level; |
|
1547 iParams.pint[1]=opt; |
|
1548 iParams.ptr[0]=(char*)buf; |
|
1549 iParams.len[0]=len; |
|
1550 return Request(PMsetsockopt,anErrno); |
|
1551 } |
|
1552 |
|
1553 TInt CProcessSystemInterface::sockname (int fid, struct sockaddr* addr, unsigned long* size, int anEnd, int& anErrno) |
|
1554 { |
|
1555 iParams.fid=fid; |
|
1556 iParams.addr.Prepare(addr); |
|
1557 iParams.pint[0]=anEnd; |
|
1558 TInt err=Request(PMsockname,anErrno); |
|
1559 if (err==0) |
|
1560 iParams.addr.Get(addr,size); |
|
1561 return err; |
|
1562 } |
|
1563 |
|
1564 TInt CProcessSystemInterface::ioctl (int fid, int cmd, void* param, int& anErrno) |
|
1565 { |
|
1566 TRequestStatus ioctlStatus; |
|
1567 TInt err=ioctl(fid,cmd,param,ioctlStatus,anErrno); |
|
1568 if (err==KErrNone) |
|
1569 { |
|
1570 User::WaitForRequest(ioctlStatus); |
|
1571 err=ioctl_complete(fid,cmd,param,ioctlStatus,anErrno); |
|
1572 } |
|
1573 return err; |
|
1574 } |
|
1575 |
|
1576 wchar_t* CProcessSystemInterface::getenv (const wchar_t* name) |
|
1577 { |
|
1578 int dummy; |
|
1579 iParams.cwptr[0]=name; |
|
1580 return (wchar_t*)Request(PMgetenv,dummy); |
|
1581 } |
|
1582 |
|
1583 void CProcessSystemInterface::unsetenv (const wchar_t* name) |
|
1584 { |
|
1585 int dummy; |
|
1586 iParams.cwptr[0]=name; |
|
1587 Request(PMunsetenv,dummy); |
|
1588 } |
|
1589 |
|
1590 int CProcessSystemInterface::setenv (const wchar_t* name, const wchar_t* value, int rewrite, int& anErrno) |
|
1591 { |
|
1592 iParams.cwptr[0]=name; |
|
1593 iParams.cwptr[1]=value; |
|
1594 iParams.pint[0]=rewrite; |
|
1595 return Request(PMsetenv,anErrno); |
|
1596 } |
|
1597 |
|
1598 int CProcessSystemInterface::popen3 (const wchar_t* file, const wchar_t* cmd, const wchar_t* mode, wchar_t** env, int fids[3], int& anErrno) |
|
1599 { |
|
1600 iParams.wptr[0]=(wchar_t*)file; |
|
1601 iParams.cwptr[0]=cmd; |
|
1602 iParams.cwptr[1]=mode; |
|
1603 iParams.eptr[0]=env; |
|
1604 iParams.pint[0]=fids[0]; |
|
1605 iParams.pint[1]=fids[1]; |
|
1606 iParams.pint[2]=fids[2]; |
|
1607 TInt child=Request(PMpopen3,anErrno); |
|
1608 if (child>=0) |
|
1609 { |
|
1610 fids[0]=iParams.pint[0]; |
|
1611 fids[1]=iParams.pint[1]; |
|
1612 fids[2]=iParams.pint[2]; |
|
1613 }; |
|
1614 return child; |
|
1615 } |
|
1616 |
|
1617 int CProcessSystemInterface::waitpid (int pid, int* status, int options, int& anErrno) |
|
1618 { |
|
1619 iParams.pint[0]=pid; |
|
1620 iParams.pint[1]=options; |
|
1621 TInt ret=Request(PMwaitpid,anErrno); |
|
1622 if (iParams.ret>=0 && status!=0) |
|
1623 { |
|
1624 *status=iParams.pint[0]; |
|
1625 return iParams.ret; |
|
1626 } |
|
1627 |
|
1628 return ret; |
|
1629 } |
|
1630 |
|
1631 // C++ version of asynchronous ioctl |
|
1632 // |
|
1633 // WARNING - this stuff is fairly insecure. We give no guarantees about whether the ioctl or |
|
1634 // the completion will read the parameter information (sometimes it's both). |
|
1635 // |
|
1636 |
|
1637 int CProcessSystemInterface::ioctl (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno) |
|
1638 { |
|
1639 iParams.fid=fid; |
|
1640 iParams.pint[0]=cmd; |
|
1641 iParams.ptr[0]=(char*)param; |
|
1642 |
|
1643 if (cmd & 0x4000) |
|
1644 Request(PMioctlN,anErrno,aStatus); |
|
1645 else |
|
1646 Request(PMioctl,anErrno,aStatus); |
|
1647 |
|
1648 return KErrNone; |
|
1649 } |
|
1650 |
|
1651 int CProcessSystemInterface::ioctl_complete (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno) |
|
1652 { |
|
1653 iParams.fid=fid; |
|
1654 iParams.pint[0]=cmd; |
|
1655 iParams.ptr[0]=(char*)param; |
|
1656 iParams.ptr[1]=(char*)&aStatus; |
|
1657 return Request(PMioctlcomplete,anErrno); |
|
1658 } |
|
1659 |
|
1660 int CProcessSystemInterface::ioctl_cancel (int /*fid*/, int& /*anErrno*/) |
|
1661 // |
|
1662 // Actually a generic Cancel function for any outstanding operation |
|
1663 // |
|
1664 { |
|
1665 TIpcArgs args; |
|
1666 return iSession.Request(PMcancel,args); |
|
1667 } |