--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/telnetengine/SRC/TELCTRL.CPP Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,507 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Symbian Telnet Control class definition
+//
+//
+
+/**
+ @file
+*/
+
+#include "TELRESOL.H"
+#include "IOBUFFER.H"
+#include "TELCTRL.H"
+#include "ACTIVEIO.H"
+#include "TELDEBUG.H"
+#include "TELFSM.H"
+
+CTelnetControl::CTelnetControl()
+/**
+Constructor
+*/
+ {
+ }
+
+CTelnetControl::~CTelnetControl()
+/**
+Destructor
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::D'Tor"));
+
+ // Active Object
+ // It's Destructor :-
+ // Close() resolver
+ // Close() socket
+ // Close() socket server
+ // Cancel's()
+ delete iTelnetResolver;
+
+ // Active Objects
+ // All Socket stuff is already closed therefore :-
+ // Their Destructors
+ // Cancel() only
+ //
+ delete iPortReader;
+ delete iPortWriter;
+
+ // Not active and no new'd resource
+ delete iPortIOControl;
+
+ // Not Active
+ // deletes all the RFC objects it new'd
+ delete iProto;
+
+ }
+
+CTelnetControl* CTelnetControl::NewL(const TTelnetConfig& aConfig,MTelnetNotification* aTelnetNotification)
+ {
+ CTelnetControl* self = new(ELeave) CTelnetControl;
+ CleanupStack::PushL(self);
+ self->ConstructL(aConfig,aTelnetNotification);
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CTelnetControl::ConstructL(const TTelnetConfig& aConfig,MTelnetNotification* aTelnetNotification)
+ {
+ iTelnetNotification = aTelnetNotification;
+
+ iPortReadBuffer.SetLength(0);
+ iClientReadBuffer.SetLength(0);
+ iClientWriteOutstanding = FALSE;
+ // Create support objects
+
+ // Create the socket handler, pass in MTelnetResolver
+ iTelnetResolver = CTelnetResolver::NewL(this);
+
+ // Create the port i/o cooperating objects
+ // IO control talks to us so pass in our MIONotification
+ iPortIOControl = CIOBufferControl::NewL(this);
+ // Port reader and write Active objects talk to PortIOControl so pass in it's MIONotification
+ iPortWriter = CActiveWriter::NewL(iPortIOControl);
+ iPortReader = CActiveReader::NewL(iPortIOControl);
+
+ // Create the Telnet Protocol handler
+ iProto = CProto::NewL(aConfig,this);
+ }
+
+// Two overloaded connect methods
+
+TInt CTelnetControl::Connect(const TDesC& aServerName, TUint aPort)
+// Use host name resolver
+ {
+ if (iTelnetResolver->State() != CTelnetResolver::EDisconnected)
+ return KErrInUse;
+ Reset();
+ TInt err;
+ err = iTelnetResolver->IssueConnect(aServerName, aPort);
+ return err;
+ }
+
+TInt CTelnetControl::Connect(const TInetAddr& aInetAddr, TUint aPort)
+// Straight IP address
+ {
+ if (iTelnetResolver->State() != CTelnetResolver::EDisconnected)
+ return KErrInUse;
+ Reset();
+ TInt err;
+ err = iTelnetResolver->IssueConnect(aInetAddr, aPort);
+ return err;
+ }
+
+void CTelnetControl::ResolverConnectedL()
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ResolverConnected()"));
+
+ // Resolver has called us back to say we're connected
+ // Give the read and write active objects a pointer to the socket
+ iPortWriter->SetSocket(iTelnetResolver->Socket());
+ iPortReader->SetSocket(iTelnetResolver->Socket());
+ iPortIOControl->SetWriter(iPortWriter);
+ iPortIOControl->SetReader(iPortReader);
+
+ TBuf8<128> tempBuffer;
+ // Call into CProto to see if we need to issue any Telnet Protocol requests following connection
+ iProto->GetInitOptions(tempBuffer);
+ if(tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length());
+ if(actionBuffer==NULL)
+ {
+ iTelnetNotification->Error(KErrNoMemory);
+ User::Leave(KErrNoMemory);
+ }
+ TPtr8 ptr = actionBuffer->Des();
+ ptr = tempBuffer;
+ if(iPortIOControl->Write(actionBuffer) != KErrNone)
+ delete actionBuffer;
+ }
+
+ // Notify the client that we've connected
+ // Client should issue first read from here
+ iTelnetNotification->Connected();
+ }
+
+void CTelnetControl::ResolverDisconnected()
+/**
+Socket handler has notified us that the TCP connection is closed
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ResolverDisconnected()"));
+
+ // M interface call to the client app
+ iTelnetNotification->ConnectionClosed();
+
+ }
+
+TInt CTelnetControl::Disconnect()
+/**
+Client app request to close the connection
+*/
+ {
+ __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::Disconnect()"));
+ // Let the socket handler do this
+ return(iTelnetResolver->IssueDisconnect());
+ }
+
+TInt CTelnetControl::Read()
+/**
+Client app has issued a read
+*/
+ {
+ if (iTelnetResolver->State() == CTelnetResolver::EDisconnected)
+ return KErrDisconnected;
+
+ iPortReadBuffer.SetLength(0);
+ return(iPortIOControl->Read(iPortReadBuffer));
+ }
+
+
+// Two overloaded write methods
+
+TInt CTelnetControl::Write(TTelnetUserControl& aControlCode)
+/**
+Sends one of the Telnet control codes defined in Telsess.h
+Certain of these characters require data to be sent as urgent
+*/
+ {
+ TInt err = KErrNone;
+
+ if (iTelnetResolver->State() != CTelnetResolver::EConnected)
+ return KErrDisconnected;
+
+
+ TBuf8<20> tempBuffer;
+ TBuf8<20> tempUrgentBuffer;
+ // Pass an ordinary buffer and a buffer for urgent data
+ if((err = iProto->ProtoWrite(aControlCode,tempBuffer,tempUrgentBuffer)) == KErrNone)
+ {
+ if(tempUrgentBuffer.Length())
+ // Urgent data to send
+ // Get a HBuf and copy
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* urgentBuffer = HBufC8::New(tempUrgentBuffer.Length());
+ if(urgentBuffer==NULL)
+ return KErrNoMemory;
+ TPtr8 urgentPtr = urgentBuffer->Des();
+ urgentPtr = tempUrgentBuffer;
+ if((err = iPortIOControl->WriteUrgent(urgentBuffer)) != KErrNone)
+ delete urgentBuffer;
+ }
+ if(err == KErrNone && tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* buffer = HBufC8::New(tempBuffer.Length());
+ if(buffer==NULL)
+ return KErrNoMemory;
+ TPtr8 ptr = buffer->Des();
+ ptr = tempBuffer;
+ if((err= iPortIOControl->Write(buffer)) != KErrNone)
+ delete buffer;
+ else
+ iClientWriteOutstanding = TRUE;
+ }
+ }
+ return(err);
+ }
+
+TInt CTelnetControl::Write(const TDesC8& aBuffer)
+/**
+Ordinary Client application write
+We allocate a heap buffer of adequate size then pass it to I/O Buffer control
+Ownership is also transferred
+*/
+ {
+
+ if(iTelnetResolver->State() != CTelnetResolver::EConnected)
+ return(KErrDisconnected);
+ if(iClientWriteOutstanding)
+ return KErrInUse;
+
+ TInt err=KErrNone;
+
+ // Create room for escapes + possible protocol appends
+ HBufC8* buffer = HBufC8::New((aBuffer.Length() * 2) + 128);
+ if(buffer==NULL)
+ return KErrNoMemory;
+ TPtr8 ptr = buffer->Des();
+
+ // Proto method performs escapes etc
+ err = iProto->ProtoWrite(aBuffer,ptr);
+
+ if(err != KErrNone || !ptr.Length())
+ {
+ delete buffer;
+ return err;
+ }
+ // Send the data to the server
+ if((err = iPortIOControl->Write(buffer)) != KErrNone)
+ delete buffer;
+ else
+ iClientWriteOutstanding = TRUE;
+ return err;
+ }
+
+TInt CTelnetControl::SetConfig(const TTelnetConfig& aConfig)
+/**
+Client call to modify Telnet Configuration
+In connected state we pass a buffer, because CProto may decide to negotiate an option
+*/
+ {
+ TInt err = KErrNone;
+ if (iTelnetResolver->State() == CTelnetResolver::EConnected)
+ {
+ TBuf8<128> tempBuffer;
+ iProto->ModifyConfig(aConfig,&tempBuffer);
+ if(tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length());
+ if(actionBuffer==NULL)
+ return KErrNoMemory;
+ TPtr8 ptr = actionBuffer->Des();
+ ptr = tempBuffer;
+ if((err = iPortIOControl->Write(actionBuffer)) != KErrNone)
+ delete actionBuffer;
+ }
+ }
+ else
+ // Config change with connection down
+ iProto->ModifyConfig(aConfig,NULL);
+ return err;
+ }
+
+
+TInt CTelnetControl::OptionStatus(TOptionStatus& aStatus)
+/**
+Client call to read the Telnet RFC options state
+*/
+ {
+ if (iTelnetResolver->State() != CTelnetResolver::EConnected)
+ return KErrDisconnected;
+ TInt err = KErrNone;
+ // Synchronous call into the CProto object
+ iProto->OptionStatus(aStatus);
+ // If RFC 859 is enabled for the Server, we can retrieve the server's perceived state of the options
+
+ TBuf8<128> tempBuffer;
+ iProto->ServerOptionStatus(tempBuffer);
+ if(tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length());
+ if(actionBuffer==NULL)
+ return KErrNoMemory;
+ TPtr8 ptr = actionBuffer->Des();
+ ptr = tempBuffer;
+ // Tell server to send it's perceived state of the RFC options
+ // Currently we do nothing with them when the server returns them
+ if((err = iPortIOControl->Write(actionBuffer)) != KErrNone)
+ delete actionBuffer;
+ }
+ return err;
+ }
+
+TInt CTelnetControl::SetOption(const TInt aOption)
+/**
+Client trying to enable an RFC option
+*/
+ {
+ if (iTelnetResolver->State() != CTelnetResolver::EConnected)
+ return KErrDisconnected;
+ TInt err = KErrNone;
+
+ TBuf8<128> tempBuffer;
+ TInt32 event;
+ // Call straight into CProto
+ iProto->ClientRequestOption(aOption,tempBuffer,event);
+ if(tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length());
+ if(actionBuffer==NULL)
+ return KErrNoMemory;
+ TPtr8 ptr = actionBuffer->Des();
+ ptr = tempBuffer;
+ // Resultant write to the server
+ if((err = iPortIOControl->Write(actionBuffer)) != KErrNone)
+ delete actionBuffer;
+ }
+ return(err);
+ }
+
+void CTelnetControl::Reset()
+/**
+Called before connection attempts
+Clears states and zeros buffers
+Calls subordinate objects to reset
+*/
+ {
+ iPortReadBuffer.SetLength(0);
+ iClientReadBuffer.SetLength(0);
+ iClientWriteOutstanding = FALSE;
+
+ iPortIOControl->Reset();
+ iProto->Reset();
+ }
+
+
+
+//
+// M Interface callbacks from CIOBufferControl
+
+void CTelnetControl::WriteComplete()
+/**
+Propogates the completion to the client if it has a write outstanding
+*/
+ {
+ if(iClientWriteOutstanding)
+ {
+ iClientWriteOutstanding = FALSE;
+ iTelnetNotification->WriteComplete();
+ }
+ }
+
+void CTelnetControl::Event(TInt aEvent,TInt aEventCode)
+/**
+Urgent data event is the only one we're intersted in
+aEventCode will be the byte that the TCP urgent pointed to
+*/
+ {
+ if(aEvent == CProto::EEventUrgentData)
+ {
+ iProto->ReceiveUrgent(aEventCode);
+ }
+ }
+
+
+void CTelnetControl::ReadCompleteL()
+ {
+ iClientReadBuffer.SetLength(0);
+ // Call into the protocol object
+ // ClientReadBuffer will have it's length set if there is client data
+ TBuf8<256> tempBuffer;
+ // Call the protocol object which will
+ iProto->ProtoRead(iPortReadBuffer,iClientReadBuffer,tempBuffer);
+
+ if(tempBuffer.Length())
+ {
+ // Allocate a heap buffer of the correct size, copy data into it and send it to buffer
+ // Control class.
+ // Ownership of the heap buffer is passed to Buffer Control
+ HBufC8* actionBuffer = HBufC8::New(tempBuffer.Length());
+ if(actionBuffer==NULL)
+ {
+ iTelnetNotification->Error(KErrNoMemory);
+ User::Leave(KErrNoMemory);
+ }
+ TPtr8 ptr = actionBuffer->Des();
+ // Copy the protocol data from stack copy
+ ptr = tempBuffer;
+ if(iPortIOControl->Write(actionBuffer) != KErrNone)
+ delete actionBuffer;
+ }
+ if(iClientReadBuffer.Length())
+ {
+ iTelnetNotification->ReadComplete(iClientReadBuffer);
+ }
+ else
+ {
+ // Re-request a read if there was no data for the client
+ iPortReadBuffer.SetLength(0);
+ iPortIOControl->Read(iPortReadBuffer);
+ }
+ }
+
+
+void CTelnetControl::ReadComplete(TInt aError)
+/**
+Will be a Read Error on the socket
+We could pass the reason up to the client but is it worth it ?
+the majority of the time it will be an ordinary disconnect.
+Log the error and start close of the socket
+*/
+ {
+ aError = aError;
+ __FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetControl::ReadComplete() Disconnect Reason = %d"),aError);
+ iTelnetResolver->HandleEof();
+ }
+
+void CTelnetControl::WriteError(TInt aError)
+/**
+Will be a Write error on the socket
+*/
+ {
+ iTelnetNotification->Error(aError);
+ }
+
+void CTelnetControl::ResolverError(TInt aError)
+/**
+Client not interested at the moment so ignore
+*/
+ {
+ iTelnetNotification->Error(aError);
+ }
+
+void CTelnetControl::ProtoError(TInt aError)
+/**
+Error from a RFC Option request
+*/
+ {
+ iTelnetNotification->Error(aError);
+ }
+
+void CTelnetControl::ProtoEvent()
+/**
+RFC Option state has changed to Enabled/Disabled
+Tell the Client
+*/
+ {
+ iTelnetNotification->OptionsChanged();
+ }