|
1 // client_command.cpp |
|
2 // |
|
3 // Copyright (c) 2009 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <fshell/ioutils.h> |
|
14 #include <fshell/ltkutils.h> |
|
15 #include "command_base.h" |
|
16 |
|
17 namespace IoUtils |
|
18 { |
|
19 |
|
20 _LIT(KNewLine, "\r\n"); |
|
21 _LIT(KOutgoingMarker, ">"); |
|
22 _LIT(KIncomingMarker, "<"); |
|
23 |
|
24 |
|
25 // |
|
26 // CServerWatcher. |
|
27 // |
|
28 |
|
29 NONSHARABLE_CLASS(CServerWatcher) : public CActive |
|
30 { |
|
31 public: |
|
32 static CServerWatcher* NewL(const TDesC& aServerExeName, CClientBase& aClient); |
|
33 ~CServerWatcher(); |
|
34 void Kill(TInt aReason); |
|
35 private: |
|
36 CServerWatcher(CClientBase& aClient); |
|
37 void ConstructL(const TDesC& aServerExeName); |
|
38 private: // From CActive. |
|
39 virtual void RunL(); |
|
40 virtual void DoCancel(); |
|
41 private: |
|
42 CClientBase& iClient; |
|
43 RProcess iServerProcess; |
|
44 }; |
|
45 |
|
46 CServerWatcher* CServerWatcher::NewL(const TDesC& aServerExeName, CClientBase& aClient) |
|
47 { |
|
48 CServerWatcher* self = new(ELeave) CServerWatcher(aClient); |
|
49 CleanupStack::PushL(self); |
|
50 self->ConstructL(aServerExeName); |
|
51 CleanupStack::Pop(self); |
|
52 return self; |
|
53 } |
|
54 |
|
55 CServerWatcher::~CServerWatcher() |
|
56 { |
|
57 Cancel(); |
|
58 iServerProcess.Close(); |
|
59 } |
|
60 |
|
61 void CServerWatcher::Kill(TInt aReason) |
|
62 { |
|
63 Cancel(); |
|
64 iServerProcess.Kill(aReason); |
|
65 } |
|
66 |
|
67 CServerWatcher::CServerWatcher(CClientBase& aClient) |
|
68 : CActive(CActive::EPriorityStandard), iClient(aClient) |
|
69 { |
|
70 CActiveScheduler::Add(this); |
|
71 } |
|
72 |
|
73 void CServerWatcher::ConstructL(const TDesC& aServerExeName) |
|
74 { |
|
75 _LIT(KWildCard, "*"); |
|
76 TName processName(aServerExeName); |
|
77 processName.Append(KWildCard); |
|
78 TFindProcess findProcess(processName); |
|
79 TFullName name; |
|
80 StaticLeaveIfErr(findProcess.Next(name), _L("Unable to find server process '%S'"), &aServerExeName); |
|
81 StaticLeaveIfErr(iServerProcess.Open(findProcess), _L("Unable to open server process '%S'"), &aServerExeName); |
|
82 if (findProcess.Next(name) != KErrNotFound) |
|
83 { |
|
84 StaticLeaveIfErr(KErrArgument, _L("Found more than one instance of '%S'"), &aServerExeName); |
|
85 } |
|
86 iServerProcess.Logon(iStatus); |
|
87 if (iStatus != KRequestPending) |
|
88 { |
|
89 User::WaitForRequest(iStatus); |
|
90 StaticLeaveIfErr(KErrGeneral, _L("Failed to logon to '%S' - %d"), &aServerExeName, iStatus.Int()); |
|
91 } |
|
92 SetActive(); |
|
93 } |
|
94 |
|
95 void CServerWatcher::RunL() |
|
96 { |
|
97 TExitCategoryName exitCategory(iServerProcess.ExitCategory()); |
|
98 iClient.HandleServerDeath(iServerProcess.ExitType(), iServerProcess.ExitReason(), exitCategory); |
|
99 } |
|
100 |
|
101 void CServerWatcher::DoCancel() |
|
102 { |
|
103 iServerProcess.LogonCancel(iStatus); |
|
104 } |
|
105 |
|
106 |
|
107 // |
|
108 // CServerReader. |
|
109 // |
|
110 |
|
111 NONSHARABLE_CLASS(CServerReader) : public CActive |
|
112 { |
|
113 public: |
|
114 static CServerReader* NewL(RIoReadHandle& aReadHandle, CClientBase& aClient); |
|
115 ~CServerReader(); |
|
116 private: |
|
117 CServerReader(RIoReadHandle& aReadHandle, CClientBase& aClient); |
|
118 void ConstructL(); |
|
119 void Queue(); |
|
120 private: // From CActive. |
|
121 virtual void RunL(); |
|
122 virtual void DoCancel(); |
|
123 private: |
|
124 RIoReadHandle& iReadHandle; |
|
125 CClientBase& iClient; |
|
126 TBuf<0x200> iLine; |
|
127 }; |
|
128 |
|
129 CServerReader* CServerReader::NewL(RIoReadHandle& aReadHandle, CClientBase& aClient) |
|
130 { |
|
131 CServerReader* self = new(ELeave) CServerReader(aReadHandle, aClient); |
|
132 CleanupStack::PushL(self); |
|
133 self->ConstructL(); |
|
134 CleanupStack::Pop(self); |
|
135 return self; |
|
136 } |
|
137 |
|
138 CServerReader::~CServerReader() |
|
139 { |
|
140 Cancel(); |
|
141 } |
|
142 |
|
143 CServerReader::CServerReader(RIoReadHandle& aReadHandle, CClientBase& aClient) |
|
144 : CActive(CActive::EPriorityStandard), iReadHandle(aReadHandle), iClient(aClient) |
|
145 { |
|
146 CActiveScheduler::Add(this); |
|
147 } |
|
148 |
|
149 void CServerReader::Queue() |
|
150 { |
|
151 iLine.Zero(); |
|
152 iReadHandle.Read(iLine, iStatus); |
|
153 SetActive(); |
|
154 } |
|
155 |
|
156 void CServerReader::ConstructL() |
|
157 { |
|
158 iReadHandle.SetReadModeL(RIoReadHandle::ELine); |
|
159 iReadHandle.SetLineSeparatorL(KNewLine()); |
|
160 Queue(); |
|
161 } |
|
162 |
|
163 void CServerReader::RunL() |
|
164 { |
|
165 TInt err = iStatus.Int(); |
|
166 if (err == KErrEof) |
|
167 { |
|
168 iClient.HandleServerReadComplete(KErrServerTerminated, iLine); |
|
169 } |
|
170 else |
|
171 { |
|
172 iClient.HandleServerReadComplete(err, iLine); |
|
173 } |
|
174 Queue(); |
|
175 } |
|
176 |
|
177 void CServerReader::DoCancel() |
|
178 { |
|
179 iReadHandle.ReadCancel(); |
|
180 } |
|
181 |
|
182 |
|
183 // |
|
184 // CServerWriter. |
|
185 // |
|
186 |
|
187 NONSHARABLE_CLASS(CServerWriter) : public CActive |
|
188 { |
|
189 public: |
|
190 static CServerWriter* NewL(RIoWriteHandle& aWriteHandle, CClientBase& aClient); |
|
191 ~CServerWriter(); |
|
192 void Write(const TDesC& aLine); |
|
193 private: |
|
194 CServerWriter(RIoWriteHandle& aWriteHandle, CClientBase& aClient); |
|
195 private: // From CActive. |
|
196 virtual void RunL(); |
|
197 virtual void DoCancel(); |
|
198 private: |
|
199 RIoWriteHandle& iWriteHandle; |
|
200 CClientBase& iClient; |
|
201 HBufC* iBuf; |
|
202 }; |
|
203 |
|
204 CServerWriter* CServerWriter::NewL(RIoWriteHandle& aWriteHandle, CClientBase& aClient) |
|
205 { |
|
206 return new(ELeave) CServerWriter(aWriteHandle, aClient); |
|
207 } |
|
208 |
|
209 CServerWriter::~CServerWriter() |
|
210 { |
|
211 Cancel(); |
|
212 delete iBuf; |
|
213 } |
|
214 |
|
215 CServerWriter::CServerWriter(RIoWriteHandle& aWriteHandle, CClientBase& aClient) |
|
216 : CActive(CActive::EPriorityStandard), iWriteHandle(aWriteHandle), iClient(aClient) |
|
217 { |
|
218 CActiveScheduler::Add(this); |
|
219 } |
|
220 |
|
221 void CServerWriter::Write(const TDesC& aLine) |
|
222 { |
|
223 ASSERT(!IsActive()); |
|
224 TInt bufferRequired = aLine.Length(); |
|
225 TBool newLineRequired(EFalse); |
|
226 if ((aLine.Length() < KNewLine().Length()) || (aLine.Right(KNewLine().Length()) != KNewLine)) |
|
227 { |
|
228 newLineRequired = ETrue; |
|
229 bufferRequired += KNewLine().Length(); |
|
230 } |
|
231 if (iBuf && (iBuf->Des().MaxLength() < bufferRequired)) |
|
232 { |
|
233 iBuf = iBuf->ReAllocL(bufferRequired); |
|
234 } |
|
235 else |
|
236 { |
|
237 iBuf = HBufC::NewL(bufferRequired); |
|
238 } |
|
239 TPtr ptr(iBuf->Des()); |
|
240 ptr.Copy(aLine); |
|
241 if (newLineRequired) |
|
242 { |
|
243 ptr.Append(KNewLine); |
|
244 } |
|
245 iWriteHandle.Write(*iBuf, iStatus); |
|
246 SetActive(); |
|
247 } |
|
248 |
|
249 void CServerWriter::RunL() |
|
250 { |
|
251 iClient.HandleServerWriteComplete(iStatus.Int()); |
|
252 } |
|
253 |
|
254 void CServerWriter::DoCancel() |
|
255 { |
|
256 iWriteHandle.WriteCancel(); |
|
257 } |
|
258 |
|
259 |
|
260 EXPORT_C CClientBase::CClientBase(TUint aFlags, const TDesC& aServerExeName, const TDesC& aPersistentConsoleName, const TDesC& aServerPrompt) |
|
261 : CCommandBase(EManualComplete | aFlags), iServerExeName(aServerExeName), iPersistentConsoleName(aPersistentConsoleName), iServerPrompt(aServerPrompt) |
|
262 { |
|
263 } |
|
264 |
|
265 EXPORT_C CClientBase::~CClientBase() |
|
266 { |
|
267 delete iCommand; |
|
268 delete iServerReader; |
|
269 delete iServerWriter; |
|
270 delete iServerWatcher; |
|
271 iServerWritePipe.Close(); |
|
272 iServerWriteHandle.Close(); |
|
273 iServerReadPipe.Close(); |
|
274 iServerReadHandle.Close(); |
|
275 iPcons.Close(); |
|
276 iServerProcess.Close(); |
|
277 iLines.ResetAndDestroy(); |
|
278 } |
|
279 |
|
280 _LIT(KWritePipeNameFmt, "%S client->server pipe"); |
|
281 _LIT(KWriterNameFmt, "%S server writer"); |
|
282 _LIT(KReadPipeNameFmt, "%S server->client pipe"); |
|
283 _LIT(KReaderNameFmt, "%S server reader"); |
|
284 |
|
285 EXPORT_C void CClientBase::DoRunL() |
|
286 { |
|
287 TInt err = iPcons.OpenByName(IoSession(), iPersistentConsoleName); |
|
288 if (err==KErrNotFound) |
|
289 { |
|
290 if (iVerbose) |
|
291 { |
|
292 Printf(_L("'%S' not found, creating...\r\n"), &iPersistentConsoleName); |
|
293 } |
|
294 LeaveIfErr(iPcons.Create(IoSession(), iPersistentConsoleName, iPersistentConsoleName), _L("Couldn't create persistent console '%S'"), &iPersistentConsoleName); |
|
295 TRAPL(iServerProcess.CreateL(iServerExeName, KNullDesC(), IoSession(), iPcons, &Env()), _L("Couldn't create server process")); |
|
296 } |
|
297 else |
|
298 { |
|
299 LeaveIfErr(err, _L("Cannot open persistent console '%S'"), &iPersistentConsoleName); |
|
300 } |
|
301 |
|
302 iServerWatcher = CServerWatcher::NewL(iServerExeName, *this); |
|
303 |
|
304 TName objName; |
|
305 |
|
306 iServerWritePipe.CreateL(IoSession()); |
|
307 objName.AppendFormat(KWritePipeNameFmt, &Name()); |
|
308 IoSession().SetObjectNameL(iServerWritePipe.SubSessionHandle(), objName); |
|
309 |
|
310 iServerWriteHandle.CreateL(IoSession()); |
|
311 objName.Zero(); |
|
312 objName.AppendFormat(KWriterNameFmt, &Name()); |
|
313 IoSession().SetObjectNameL(iServerWriteHandle.SubSessionHandle(), objName); |
|
314 iServerWriteHandle.SetModeL(RIoWriteHandle::EText); |
|
315 iServerWritePipe.AttachL(iServerWriteHandle); |
|
316 // attach the pcons reader to the other end of our server write pipe |
|
317 LeaveIfErr(iPcons.AttachReader(iServerWritePipe, RIoPersistentConsole::EDetachOnHandleClose), _L("Cannot connect reader to persistent console %S"), &iPersistentConsoleName); |
|
318 iServerWriter = CServerWriter::NewL(iServerWriteHandle, *this); |
|
319 |
|
320 iServerReadPipe.CreateL(IoSession()); |
|
321 objName.Zero(); |
|
322 objName.AppendFormat(KReadPipeNameFmt, &Name()); |
|
323 IoSession().SetObjectNameL(iServerReadPipe.SubSessionHandle(), objName); |
|
324 |
|
325 iServerReadHandle.CreateL(IoSession()); |
|
326 objName.Zero(); |
|
327 objName.AppendFormat(KReaderNameFmt, &Name()); |
|
328 IoSession().SetObjectNameL(iServerReadHandle.SubSessionHandle(), objName); |
|
329 iServerReadPipe.AttachL(iServerReadHandle, RIoEndPoint::EForeground); |
|
330 // attach the pcons writer to the other end of our server read pipe |
|
331 LeaveIfErr(iPcons.AttachWriter(iServerReadPipe, RIoPersistentConsole::EDetachOnHandleClose), _L("Cannot connect writer to persistent console %S"), &iPersistentConsoleName); |
|
332 iServerReader = CServerReader::NewL(iServerReadHandle, *this); |
|
333 |
|
334 if (iServerProcess.Process().Handle() != KNullHandle && iServerProcess.Process().Handle() != RProcess().Handle()) |
|
335 { |
|
336 // We created a new server process, but it's not yet been resumed. |
|
337 iServerProcess.Detach(); // Note, iServerWatch has already logged onto the process so there's no need to use RChildProcess::Run. |
|
338 iWaitingForServerPrompt = ETrue; |
|
339 } |
|
340 else |
|
341 { |
|
342 // The server was already running - no need to wait for a prompt, go ahead and write the command. |
|
343 SendCommand(); |
|
344 } |
|
345 } |
|
346 |
|
347 EXPORT_C void CClientBase::ArgumentsL(RCommandArgumentList& aArguments) |
|
348 { |
|
349 _LIT(KCommand, "command"); |
|
350 |
|
351 if (UsingCif()) // Test this dynamically for the time being because not all sub-classes have been migrated to CIFs. |
|
352 { |
|
353 aArguments.AppendStringL(iCommand, KCommand); |
|
354 } |
|
355 else |
|
356 { |
|
357 _LIT(KCommandDescription, "The command to run."); |
|
358 aArguments.AppendStringL(iCommand, KCommand, KCommandDescription, KValueTypeFlagLast); |
|
359 } |
|
360 } |
|
361 |
|
362 EXPORT_C void CClientBase::HandleLeave(TInt aError) |
|
363 { |
|
364 CCommandBase::HandleLeave(aError); |
|
365 } |
|
366 |
|
367 void CClientBase::HandleServerReadComplete(TInt aError, TDes& aLine) |
|
368 { |
|
369 if (aError == KErrEof) |
|
370 { |
|
371 Complete(KErrNone); |
|
372 } |
|
373 else if (aError) |
|
374 { |
|
375 iServerWatcher->Kill(KErrAbort); |
|
376 Complete(aError, _L("Failed to read server response")); |
|
377 } |
|
378 else if (aLine == iServerPrompt) |
|
379 { |
|
380 if (iWaitingForServerPrompt) |
|
381 { |
|
382 iWaitingForServerPrompt = EFalse; |
|
383 SendCommand(); |
|
384 } |
|
385 else |
|
386 { |
|
387 TRAPD(err, HandleServerResponseL(iLines)); |
|
388 Complete(err); |
|
389 } |
|
390 } |
|
391 else |
|
392 { |
|
393 if (iVerbose) |
|
394 { |
|
395 Write(KIncomingMarker); |
|
396 Write(aLine); |
|
397 } |
|
398 if (!iWaitingForServerPrompt) |
|
399 { |
|
400 aLine.TrimRight(); |
|
401 HBufC* buf = aLine.AllocLC(); |
|
402 iLines.AppendL(buf); |
|
403 CleanupStack::Pop(buf); |
|
404 } |
|
405 } |
|
406 } |
|
407 |
|
408 void CClientBase::HandleServerWriteComplete(TInt aError) |
|
409 { |
|
410 if (aError) |
|
411 { |
|
412 iServerWatcher->Kill(KErrAbort); |
|
413 Complete(aError, _L("Failed to write command to server")); |
|
414 } |
|
415 } |
|
416 |
|
417 void CClientBase::HandleServerDeath(TExitType aExitType, TInt aExitReason, const TDesC& aExitCategory) |
|
418 { |
|
419 if (aExitType == EExitPanic) |
|
420 { |
|
421 Complete(KErrServerTerminated, _L("Server '%S' PANIC - %S %d"), &iServerExeName, &aExitCategory, aExitReason); |
|
422 } |
|
423 else if (aExitReason) |
|
424 { |
|
425 Complete(aExitReason, _L("Server '%S' exitied abnormally"), &iServerExeName); |
|
426 } |
|
427 else |
|
428 { |
|
429 Complete(); |
|
430 } |
|
431 } |
|
432 |
|
433 void CClientBase::SendCommand() |
|
434 { |
|
435 if (iVerbose) |
|
436 { |
|
437 Write(KOutgoingMarker); |
|
438 Write(*iCommand); |
|
439 Write(KNewLine); |
|
440 } |
|
441 iServerWriter->Write(*iCommand); |
|
442 } |
|
443 |
|
444 } // namespace IoUtils |
|
445 |