|
1 // Copyright (c) 2003-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 // Symbian Telnet Control class definition |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 */ |
|
21 |
|
22 #include "TELRESOL.H" |
|
23 #include "IOBUFFER.H" |
|
24 #include "TELCTRL.H" |
|
25 #include "ACTIVEIO.H" |
|
26 #include "TELDEBUG.H" |
|
27 #include "TELFSM.H" |
|
28 |
|
29 CTelnetControl::CTelnetControl() |
|
30 /** |
|
31 Constructor |
|
32 */ |
|
33 { |
|
34 } |
|
35 |
|
36 CTelnetControl::~CTelnetControl() |
|
37 /** |
|
38 Destructor |
|
39 */ |
|
40 { |
|
41 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::D'Tor")); |
|
42 |
|
43 // Active Object |
|
44 // It's Destructor :- |
|
45 // Close() resolver |
|
46 // Close() socket |
|
47 // Close() socket server |
|
48 // Cancel's() |
|
49 delete iTelnetResolver; |
|
50 |
|
51 // Active Objects |
|
52 // All Socket stuff is already closed therefore :- |
|
53 // Their Destructors |
|
54 // Cancel() only |
|
55 // |
|
56 delete iPortReader; |
|
57 delete iPortWriter; |
|
58 |
|
59 // Not active and no new'd resource |
|
60 delete iPortIOControl; |
|
61 |
|
62 // Not Active |
|
63 // deletes all the RFC objects it new'd |
|
64 delete iProto; |
|
65 |
|
66 } |
|
67 |
|
68 CTelnetControl* CTelnetControl::NewL(const TTelnetConfig& aConfig,MTelnetNotification* aTelnetNotification) |
|
69 { |
|
70 CTelnetControl* self = new(ELeave) CTelnetControl; |
|
71 CleanupStack::PushL(self); |
|
72 self->ConstructL(aConfig,aTelnetNotification); |
|
73 CleanupStack::Pop(); |
|
74 return self; |
|
75 } |
|
76 |
|
77 void CTelnetControl::ConstructL(const TTelnetConfig& aConfig,MTelnetNotification* aTelnetNotification) |
|
78 { |
|
79 iTelnetNotification = aTelnetNotification; |
|
80 |
|
81 iPortReadBuffer.SetLength(0); |
|
82 iClientReadBuffer.SetLength(0); |
|
83 iClientWriteOutstanding = FALSE; |
|
84 // Create support objects |
|
85 |
|
86 // Create the socket handler, pass in MTelnetResolver |
|
87 iTelnetResolver = CTelnetResolver::NewL(this); |
|
88 |
|
89 // Create the port i/o cooperating objects |
|
90 // IO control talks to us so pass in our MIONotification |
|
91 iPortIOControl = CIOBufferControl::NewL(this); |
|
92 // Port reader and write Active objects talk to PortIOControl so pass in it's MIONotification |
|
93 iPortWriter = CActiveWriter::NewL(iPortIOControl); |
|
94 iPortReader = CActiveReader::NewL(iPortIOControl); |
|
95 |
|
96 // Create the Telnet Protocol handler |
|
97 iProto = CProto::NewL(aConfig,this); |
|
98 } |
|
99 |
|
100 // Two overloaded connect methods |
|
101 |
|
102 TInt CTelnetControl::Connect(const TDesC& aServerName, TUint aPort) |
|
103 // Use host name resolver |
|
104 { |
|
105 if (iTelnetResolver->State() != CTelnetResolver::EDisconnected) |
|
106 return KErrInUse; |
|
107 Reset(); |
|
108 TInt err; |
|
109 err = iTelnetResolver->IssueConnect(aServerName, aPort); |
|
110 return err; |
|
111 } |
|
112 |
|
113 TInt CTelnetControl::Connect(const TInetAddr& aInetAddr, TUint aPort) |
|
114 // Straight IP address |
|
115 { |
|
116 if (iTelnetResolver->State() != CTelnetResolver::EDisconnected) |
|
117 return KErrInUse; |
|
118 Reset(); |
|
119 TInt err; |
|
120 err = iTelnetResolver->IssueConnect(aInetAddr, aPort); |
|
121 return err; |
|
122 } |
|
123 |
|
124 void CTelnetControl::ResolverConnectedL() |
|
125 { |
|
126 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ResolverConnected()")); |
|
127 |
|
128 // Resolver has called us back to say we're connected |
|
129 // Give the read and write active objects a pointer to the socket |
|
130 iPortWriter->SetSocket(iTelnetResolver->Socket()); |
|
131 iPortReader->SetSocket(iTelnetResolver->Socket()); |
|
132 iPortIOControl->SetWriter(iPortWriter); |
|
133 iPortIOControl->SetReader(iPortReader); |
|
134 |
|
135 TBuf8<128> tempBuffer; |
|
136 // Call into CProto to see if we need to issue any Telnet Protocol requests following connection |
|
137 iProto->GetInitOptions(tempBuffer); |
|
138 if(tempBuffer.Length()) |
|
139 { |
|
140 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
141 // Control class. |
|
142 // Ownership of the heap buffer is passed to Buffer Control |
|
143 HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length()); |
|
144 if(actionBuffer==NULL) |
|
145 { |
|
146 iTelnetNotification->Error(KErrNoMemory); |
|
147 User::Leave(KErrNoMemory); |
|
148 } |
|
149 TPtr8 ptr = actionBuffer->Des(); |
|
150 ptr = tempBuffer; |
|
151 if(iPortIOControl->Write(actionBuffer) != KErrNone) |
|
152 delete actionBuffer; |
|
153 } |
|
154 |
|
155 // Notify the client that we've connected |
|
156 // Client should issue first read from here |
|
157 iTelnetNotification->Connected(); |
|
158 } |
|
159 |
|
160 void CTelnetControl::ResolverDisconnected() |
|
161 /** |
|
162 Socket handler has notified us that the TCP connection is closed |
|
163 */ |
|
164 { |
|
165 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ResolverDisconnected()")); |
|
166 |
|
167 // M interface call to the client app |
|
168 iTelnetNotification->ConnectionClosed(); |
|
169 |
|
170 } |
|
171 |
|
172 TInt CTelnetControl::Disconnect() |
|
173 /** |
|
174 Client app request to close the connection |
|
175 */ |
|
176 { |
|
177 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::Disconnect()")); |
|
178 // Let the socket handler do this |
|
179 return(iTelnetResolver->IssueDisconnect()); |
|
180 } |
|
181 |
|
182 TInt CTelnetControl::Read() |
|
183 /** |
|
184 Client app has issued a read |
|
185 */ |
|
186 { |
|
187 if (iTelnetResolver->State() == CTelnetResolver::EDisconnected) |
|
188 return KErrDisconnected; |
|
189 |
|
190 iPortReadBuffer.SetLength(0); |
|
191 return(iPortIOControl->Read(iPortReadBuffer)); |
|
192 } |
|
193 |
|
194 |
|
195 // Two overloaded write methods |
|
196 |
|
197 TInt CTelnetControl::Write(TTelnetUserControl& aControlCode) |
|
198 /** |
|
199 Sends one of the Telnet control codes defined in Telsess.h |
|
200 Certain of these characters require data to be sent as urgent |
|
201 */ |
|
202 { |
|
203 TInt err = KErrNone; |
|
204 |
|
205 if (iTelnetResolver->State() != CTelnetResolver::EConnected) |
|
206 return KErrDisconnected; |
|
207 |
|
208 |
|
209 TBuf8<20> tempBuffer; |
|
210 TBuf8<20> tempUrgentBuffer; |
|
211 // Pass an ordinary buffer and a buffer for urgent data |
|
212 if((err = iProto->ProtoWrite(aControlCode,tempBuffer,tempUrgentBuffer)) == KErrNone) |
|
213 { |
|
214 if(tempUrgentBuffer.Length()) |
|
215 // Urgent data to send |
|
216 // Get a HBuf and copy |
|
217 { |
|
218 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
219 // Control class. |
|
220 // Ownership of the heap buffer is passed to Buffer Control |
|
221 HBufC8* urgentBuffer = HBufC8::New(tempUrgentBuffer.Length()); |
|
222 if(urgentBuffer==NULL) |
|
223 return KErrNoMemory; |
|
224 TPtr8 urgentPtr = urgentBuffer->Des(); |
|
225 urgentPtr = tempUrgentBuffer; |
|
226 if((err = iPortIOControl->WriteUrgent(urgentBuffer)) != KErrNone) |
|
227 delete urgentBuffer; |
|
228 } |
|
229 if(err == KErrNone && tempBuffer.Length()) |
|
230 { |
|
231 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
232 // Control class. |
|
233 // Ownership of the heap buffer is passed to Buffer Control |
|
234 HBufC8* buffer = HBufC8::New(tempBuffer.Length()); |
|
235 if(buffer==NULL) |
|
236 return KErrNoMemory; |
|
237 TPtr8 ptr = buffer->Des(); |
|
238 ptr = tempBuffer; |
|
239 if((err= iPortIOControl->Write(buffer)) != KErrNone) |
|
240 delete buffer; |
|
241 else |
|
242 iClientWriteOutstanding = TRUE; |
|
243 } |
|
244 } |
|
245 return(err); |
|
246 } |
|
247 |
|
248 TInt CTelnetControl::Write(const TDesC8& aBuffer) |
|
249 /** |
|
250 Ordinary Client application write |
|
251 We allocate a heap buffer of adequate size then pass it to I/O Buffer control |
|
252 Ownership is also transferred |
|
253 */ |
|
254 { |
|
255 |
|
256 if(iTelnetResolver->State() != CTelnetResolver::EConnected) |
|
257 return(KErrDisconnected); |
|
258 if(iClientWriteOutstanding) |
|
259 return KErrInUse; |
|
260 |
|
261 TInt err=KErrNone; |
|
262 |
|
263 // Create room for escapes + possible protocol appends |
|
264 HBufC8* buffer = HBufC8::New((aBuffer.Length() * 2) + 128); |
|
265 if(buffer==NULL) |
|
266 return KErrNoMemory; |
|
267 TPtr8 ptr = buffer->Des(); |
|
268 |
|
269 // Proto method performs escapes etc |
|
270 err = iProto->ProtoWrite(aBuffer,ptr); |
|
271 |
|
272 if(err != KErrNone || !ptr.Length()) |
|
273 { |
|
274 delete buffer; |
|
275 return err; |
|
276 } |
|
277 // Send the data to the server |
|
278 if((err = iPortIOControl->Write(buffer)) != KErrNone) |
|
279 delete buffer; |
|
280 else |
|
281 iClientWriteOutstanding = TRUE; |
|
282 return err; |
|
283 } |
|
284 |
|
285 TInt CTelnetControl::SetConfig(const TTelnetConfig& aConfig) |
|
286 /** |
|
287 Client call to modify Telnet Configuration |
|
288 In connected state we pass a buffer, because CProto may decide to negotiate an option |
|
289 */ |
|
290 { |
|
291 TInt err = KErrNone; |
|
292 if (iTelnetResolver->State() == CTelnetResolver::EConnected) |
|
293 { |
|
294 TBuf8<128> tempBuffer; |
|
295 iProto->ModifyConfig(aConfig,&tempBuffer); |
|
296 if(tempBuffer.Length()) |
|
297 { |
|
298 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
299 // Control class. |
|
300 // Ownership of the heap buffer is passed to Buffer Control |
|
301 HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length()); |
|
302 if(actionBuffer==NULL) |
|
303 return KErrNoMemory; |
|
304 TPtr8 ptr = actionBuffer->Des(); |
|
305 ptr = tempBuffer; |
|
306 if((err = iPortIOControl->Write(actionBuffer)) != KErrNone) |
|
307 delete actionBuffer; |
|
308 } |
|
309 } |
|
310 else |
|
311 // Config change with connection down |
|
312 iProto->ModifyConfig(aConfig,NULL); |
|
313 return err; |
|
314 } |
|
315 |
|
316 |
|
317 TInt CTelnetControl::OptionStatus(TOptionStatus& aStatus) |
|
318 /** |
|
319 Client call to read the Telnet RFC options state |
|
320 */ |
|
321 { |
|
322 if (iTelnetResolver->State() != CTelnetResolver::EConnected) |
|
323 return KErrDisconnected; |
|
324 TInt err = KErrNone; |
|
325 // Synchronous call into the CProto object |
|
326 iProto->OptionStatus(aStatus); |
|
327 // If RFC 859 is enabled for the Server, we can retrieve the server's perceived state of the options |
|
328 |
|
329 TBuf8<128> tempBuffer; |
|
330 iProto->ServerOptionStatus(tempBuffer); |
|
331 if(tempBuffer.Length()) |
|
332 { |
|
333 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
334 // Control class. |
|
335 // Ownership of the heap buffer is passed to Buffer Control |
|
336 HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length()); |
|
337 if(actionBuffer==NULL) |
|
338 return KErrNoMemory; |
|
339 TPtr8 ptr = actionBuffer->Des(); |
|
340 ptr = tempBuffer; |
|
341 // Tell server to send it's perceived state of the RFC options |
|
342 // Currently we do nothing with them when the server returns them |
|
343 if((err = iPortIOControl->Write(actionBuffer)) != KErrNone) |
|
344 delete actionBuffer; |
|
345 } |
|
346 return err; |
|
347 } |
|
348 |
|
349 TInt CTelnetControl::SetOption(const TInt aOption) |
|
350 /** |
|
351 Client trying to enable an RFC option |
|
352 */ |
|
353 { |
|
354 if (iTelnetResolver->State() != CTelnetResolver::EConnected) |
|
355 return KErrDisconnected; |
|
356 TInt err = KErrNone; |
|
357 |
|
358 TBuf8<128> tempBuffer; |
|
359 TInt32 event; |
|
360 // Call straight into CProto |
|
361 iProto->ClientRequestOption(aOption,tempBuffer,event); |
|
362 if(tempBuffer.Length()) |
|
363 { |
|
364 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
365 // Control class. |
|
366 // Ownership of the heap buffer is passed to Buffer Control |
|
367 HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length()); |
|
368 if(actionBuffer==NULL) |
|
369 return KErrNoMemory; |
|
370 TPtr8 ptr = actionBuffer->Des(); |
|
371 ptr = tempBuffer; |
|
372 // Resultant write to the server |
|
373 if((err = iPortIOControl->Write(actionBuffer)) != KErrNone) |
|
374 delete actionBuffer; |
|
375 } |
|
376 return(err); |
|
377 } |
|
378 |
|
379 void CTelnetControl::Reset() |
|
380 /** |
|
381 Called before connection attempts |
|
382 Clears states and zeros buffers |
|
383 Calls subordinate objects to reset |
|
384 */ |
|
385 { |
|
386 iPortReadBuffer.SetLength(0); |
|
387 iClientReadBuffer.SetLength(0); |
|
388 iClientWriteOutstanding = FALSE; |
|
389 |
|
390 iPortIOControl->Reset(); |
|
391 iProto->Reset(); |
|
392 } |
|
393 |
|
394 |
|
395 |
|
396 // |
|
397 // M Interface callbacks from CIOBufferControl |
|
398 |
|
399 void CTelnetControl::WriteComplete() |
|
400 /** |
|
401 Propogates the completion to the client if it has a write outstanding |
|
402 */ |
|
403 { |
|
404 if(iClientWriteOutstanding) |
|
405 { |
|
406 iClientWriteOutstanding = FALSE; |
|
407 iTelnetNotification->WriteComplete(); |
|
408 } |
|
409 } |
|
410 |
|
411 void CTelnetControl::Event(TInt aEvent,TInt aEventCode) |
|
412 /** |
|
413 Urgent data event is the only one we're intersted in |
|
414 aEventCode will be the byte that the TCP urgent pointed to |
|
415 */ |
|
416 { |
|
417 if(aEvent == CProto::EEventUrgentData) |
|
418 { |
|
419 iProto->ReceiveUrgent(aEventCode); |
|
420 } |
|
421 } |
|
422 |
|
423 |
|
424 void CTelnetControl::ReadCompleteL() |
|
425 { |
|
426 iClientReadBuffer.SetLength(0); |
|
427 // Call into the protocol object |
|
428 // ClientReadBuffer will have it's length set if there is client data |
|
429 TBuf8<256> tempBuffer; |
|
430 // Call the protocol object which will |
|
431 iProto->ProtoRead(iPortReadBuffer,iClientReadBuffer,tempBuffer); |
|
432 |
|
433 if(tempBuffer.Length()) |
|
434 { |
|
435 // Allocate a heap buffer of the correct size, copy data into it and send it to buffer |
|
436 // Control class. |
|
437 // Ownership of the heap buffer is passed to Buffer Control |
|
438 HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length()); |
|
439 if(actionBuffer==NULL) |
|
440 { |
|
441 iTelnetNotification->Error(KErrNoMemory); |
|
442 User::Leave(KErrNoMemory); |
|
443 } |
|
444 TPtr8 ptr = actionBuffer->Des(); |
|
445 // Copy the protocol data from stack copy |
|
446 ptr = tempBuffer; |
|
447 if(iPortIOControl->Write(actionBuffer) != KErrNone) |
|
448 delete actionBuffer; |
|
449 } |
|
450 if(iClientReadBuffer.Length()) |
|
451 { |
|
452 iTelnetNotification->ReadComplete(iClientReadBuffer); |
|
453 } |
|
454 else |
|
455 { |
|
456 // Re-request a read if there was no data for the client |
|
457 iPortReadBuffer.SetLength(0); |
|
458 iPortIOControl->Read(iPortReadBuffer); |
|
459 } |
|
460 } |
|
461 |
|
462 |
|
463 void CTelnetControl::ReadComplete(TInt aError) |
|
464 /** |
|
465 Will be a Read Error on the socket |
|
466 We could pass the reason up to the client but is it worth it ? |
|
467 the majority of the time it will be an ordinary disconnect. |
|
468 Log the error and start close of the socket |
|
469 */ |
|
470 { |
|
471 aError = aError; |
|
472 __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ReadComplete() Disconnect Reason = %d"),aError); |
|
473 iTelnetResolver->HandleEof(); |
|
474 } |
|
475 |
|
476 void CTelnetControl::WriteError(TInt aError) |
|
477 /** |
|
478 Will be a Write error on the socket |
|
479 */ |
|
480 { |
|
481 iTelnetNotification->Error(aError); |
|
482 } |
|
483 |
|
484 void CTelnetControl::ResolverError(TInt aError) |
|
485 /** |
|
486 Client not interested at the moment so ignore |
|
487 */ |
|
488 { |
|
489 iTelnetNotification->Error(aError); |
|
490 } |
|
491 |
|
492 void CTelnetControl::ProtoError(TInt aError) |
|
493 /** |
|
494 Error from a RFC Option request |
|
495 */ |
|
496 { |
|
497 iTelnetNotification->Error(aError); |
|
498 } |
|
499 |
|
500 void CTelnetControl::ProtoEvent() |
|
501 /** |
|
502 RFC Option state has changed to Enabled/Disabled |
|
503 Tell the Client |
|
504 */ |
|
505 { |
|
506 iTelnetNotification->OptionsChanged(); |
|
507 } |