--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_intsock.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,3237 @@
+// Copyright (c) 2007-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:
+//
+
+#define SYMBIAN_NETWORKING_UPS
+
+#include <es_prot.h>
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include "es_mbufif.h"
+#include <ss_glob.h>
+#include <ss_protprov.h>
+#include <comms-infras/ss_sapshim.h>
+#include <comms-infras/ss_intsock.h>
+#include <in_sock.h>
+#include "ss_flowrequest.h"
+#include "ss_sapfactshim.h"
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/cfmacro.h>
+#include <comms-infras/ss_msgintercept.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <es_sock_internal.h>
+#endif
+
+#ifdef SYMBIAN_NETWORKING_UPS
+#include <comms-infras/ss_platsec_apiext.h> // MPlatSecApiExt
+#endif //SYMBIAN_NETWORKING_UPS
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ESockSSocksntsck, "ESockSSocksntsck");
+#endif
+
+
+using namespace ESock;
+using namespace Messages;
+using namespace Factories;
+using namespace Den;
+
+/**
+ @internalComponent
+ */
+const TUint KAllSelectFlags = (KSockSelectRead | KSockSelectWrite | KSockSelectExcept);
+
+#define MSG_PRM(prmIndex) (prmIndex)
+
+
+ASocket::ASocket(TInt aSocketType)
+ : iSocketType(aSocketType),
+ iIsFlowRequestPending(EFalse)
+/**
+ Constructor - set up default options.
+ */
+ {
+ }
+
+const RNodeInterface* ASocket::ServiceProvider() const
+ {
+ return iServiceProvider.IsOpen()? &iServiceProvider : NULL;
+ }
+
+TBool ASocket::GetFlowAndSCPR(Messages::TNodeId& aFlow, Messages::TNodeId& aSCPR) const
+ {
+ if (iFlowBinder)
+ {
+ aFlow = iFlowBinder->Flow()->Id();
+ aSCPR = iFlowBinder->Flow()->ControlProvider().RecipientId();
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+void ASocket::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+ {
+ (void) aRecipient;
+ ESOCK_DEBUG_MESSAGE_INTERCEPT(aSender, aMessage, aRecipient);
+
+ if (aMessage.IsMessage<TEBase::TError>())
+ {
+ // The first error would be from the flow request, any other error iIsFlowRequestPending must be false anyway
+ if (FlowRequestPending())
+ {
+ TEBase::TError& errorMsg(static_cast<TEBase::TError&>(aMessage));
+ CompleteFlowRequestMessage(errorMsg.iValue);
+ SetFlowRequestPending(EFalse);
+ }
+ //We are no longer needed and the client has been completed too, tear us down.
+ InitiateDestruction();
+ }
+ else if (aMessage.IsMessage<TCFDataClient::TBindTo>())
+ {
+ TCFDataClient::TBindTo& bindToMsg(static_cast<TCFDataClient::TBindTo&>(aMessage));
+
+ TInt err;
+ if (IsClosing())
+ {
+ err = KErrAbort;
+ }
+ else
+ {
+ TRAP(err,BindToL(bindToMsg));
+ }
+
+ RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(err).CRef());
+
+ CompleteFlowRequestMessage(err);
+ SetFlowRequestPending(EFalse);
+
+ if ( IsClosing () )
+ InitiateDestruction ();
+ }
+ else
+ {
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksntsck, 1));
+ }
+ }
+
+void ASocket::BindToL(const TCFDataClient::TBindTo& aBindTo)
+ {
+ __ASSERT_DEBUG(iSSP==NULL, User::Panic(KSpecAssert_ESockSSocksntsck, 2));
+
+#ifdef SYMBIAN_NETWORKING_UPS
+ LOG(ESockLog::Printf(_L8("CSocket %08x:\tBindToL(%08x)"), this, &aBindTo.iNodeId.Node()) );
+ LOG(ESockLogExternal::Printf(KCFNodeTag, KESockFlowTag, _L8("CSocket %08x:\tSynchronous call: Sender=%08x, Recipient=%08x, Function=BindToL"), this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) );
+#endif
+
+#if defined(__GCCXML__)
+ CSubConnectionFlowBase* flow = reinterpret_cast<CSubConnectionFlowBase*>(
+ reinterpret_cast<Messages::ANode*>(
+ aBindTo.iNodeId.Ptr()
+ )
+ );
+#else
+ CSubConnectionFlowBase* flow = mcfnode_cast<CSubConnectionFlowBase>(
+ reinterpret_cast<Messages::ANode*>(
+ aBindTo.iNodeId.Ptr()
+ )
+ );
+#endif
+
+ if (flow==NULL)
+ {
+ NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL Error flow is null"),
+ this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+ User::Leave(KErrArgument);
+ }
+
+ NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"),
+ this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+
+ // Perform the binding to the flow below
+ iFlowBinder = flow->GetBinderControlL();
+ iServiceProvider.Open(iFlowBinder->Flow()->Id());
+ iSSP = iFlowBinder->GetControlL(iProtocolInfo->iSockType, *this);
+ iSSPData = iFlowBinder->BindL(*this);
+
+ if(RequiresOwnerInfo())
+ {
+ CommunicateOwner();
+ }
+
+ // ask the socket provider to perform security policy checking
+ TInt ret = SecurityCheck();
+ NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=SecurityCheck Result Error Code=%d"),
+ this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node(), ret) )
+ User::LeaveIfError(ret);
+ iSSP->Start();
+ }
+
+
+void ASocket::AcceptSetupL(const ASocket& aParentSocket, CSubConnectionFlowBase& aFlow)
+/**
+Copy constructor type thing for Accept
+Takes all the useful info from a parent socket, sets up the supplied SSP and
+Other default values.
+*/
+ {
+ iOptions = aParentSocket.iOptions;
+ iProtocolInfo = aParentSocket.iProtocolInfo;
+
+ __ASSERT_DEBUG(iFlowBinder==NULL, User::Panic(KSpecAssert_ESockSSocksntsck, 3));
+ iFlowBinder = aFlow.GetBinderControlL();
+ iSSP = iFlowBinder->GetControlL(iProtocolInfo->iSockType, *this);
+ iSSPData = iFlowBinder->BindL(*this);
+ iIsBound=ETrue;
+
+ iRecBufSize=aParentSocket.iRecBufSize;
+ iSendBufSize=aParentSocket.iSendBufSize;
+ }
+
+void ASocket::Create(TServerProtocolDesc *aServiceInfo)
+/**
+Create for all sockets.
+*/
+ {
+ /** We create non connection orinted sockets "Open" and sockets without an ssp "NULL" */
+ if (!aServiceInfo)
+ {
+ SetState(ESStateNull);
+ UnregisterSelf(); // Null sockets need no cookie (and subsequently trying to deregister from a different Accept()ing Player is problematic and adds no benefit
+ }
+ else
+ {
+ iProtocolInfo=aServiceInfo;
+ if (!IsConnectionOriented())
+ {
+ SetState(ESStateOpen);
+ }
+ }
+
+ iOptions=KESocketDefaultOptions;
+ iIsBound=EFalse;
+
+#ifdef ESOCK_GULP
+ // allocate extra memory for experimental gulp implementation
+ iRecBufSize=KSocketDefaultBufferSize * 4;
+#else
+ iRecBufSize=KSocketDefaultBufferSize;
+#endif
+ iSendBufSize=KSocketDefaultBufferSize;
+ }
+
+
+ASocket::~ASocket()
+/**
+Socket destructor. Will ensure that the SSP (and any accept queue) is shutdown before destroying it.
+Automatically completes all outstanding requests.
+
+*/
+ {
+ iServiceProvider.Close();
+
+ delete iDisconnectData;
+ iDatagramTail.Free(); // we should normally have done this in closing
+ iSendData.Free(); // we should normally have done this in closing
+
+ if (iAcceptQ)
+ {
+ while (iAcceptQ->Count())
+ {
+ TAcceptQEntry a;
+ iAcceptQ->Remove(&a);
+
+ // the SSPs on an accept queue shouldn't have been Start()ed so we don't need to shut them down.
+ // a.iSSP->DeleteMeNow(); // destruction no longer synchronous & vertical
+ CTransportFlowShim* shimFlow = factoryobject_cast<CTransportFlowShim>(a.iSSP);
+
+ // The SAP is no longer owned by the listener socket.
+ shimFlow->iListenerControlNotify = NULL;
+
+ shimFlow->InitDestroy();
+ delete a.iConnectData;
+ }
+ delete iAcceptQ;
+ }
+ delete iNextAcceptQ;
+ delete iAllocAsync;
+
+ delete iCurrentMsg;
+ delete iReadMsg;
+ delete iWriteMsg;
+ delete iBlockedCloseMsg;
+ delete iBlockedConnectMsg;
+ delete iBlockedIoctlMsg;
+ delete iBlockedSetLocalNameMsg;
+ }
+
+void ASocket::InitiateDestruction()
+ {
+ SetClosing();
+
+ if (iSSP)
+ {
+ if ((State()==ESStateOpeningActive || State()==ESStateOpeningPassive
+ || State()==ESStateOpen || State()==ESStateConnected
+|| State()==ESStateBinding
+ ))
+ {
+ iSSP->Shutdown(MSessionControl::EImmediate);
+ }
+
+ __ASSERT_DEBUG(iFlowBinder, User::Panic(KSpecAssert_ESockSSocksntsck, 4));
+ iFlowBinder->Unbind();
+ }
+
+ /*
+ CSubConnectionFlowBase* flow = iFlowBinder->Flow();
+ if(!flow->HasControlPlane())
+ {
+ CNetworkFlow* netFlow = static_cast<CNetworkFlow*>(flow);
+ delete netFlow;
+ iSSP = NULL;
+ delete this;
+ }
+
+ }
+ else
+ {
+ // Either stillborn with OOM or after Shutdown() has detached
+ delete this;
+ }
+ */
+ }
+
+void ASocket::ShutdownL(RSocket::TShutdown aType, TBool aDisconnectData)
+/**
+Terminate the protocol
+*/
+ {
+ if (State()==ESStateShuttingDown)
+ {
+ PanicSocketClient(EShutDownTwice);
+ return;
+ }
+
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ MSessionControl::TCloseType h=MSessionControl::ENormal;
+ if (SupportsGracefulClose())
+ {
+ switch (aType)
+ {
+ case RSocket::ENormal:
+ CompleteWrite(KErrCancel);
+ CompleteRead(KErrCancel);
+ h=MSessionControl::ENormal;
+ iBlockedOperations|=(EReadStopped|EWriteStopped);
+ break;
+ case RSocket::EStopInput:
+ CompleteRead(KErrCancel);
+ h=MSessionControl::EStopInput;
+ iBlockedOperations|=EReadStopped;
+ iDatagramTail.Free();
+ break;
+ case RSocket::EStopOutput:
+ h=MSessionControl::EStopOutput;
+ iBlockedOperations|=EWriteStopped;
+ CompleteWrite(KErrCancel);
+ break;
+ case RSocket::EImmediate:
+ h=MSessionControl::EImmediate;
+ CompleteWrite(KErrCancel);
+ CompleteRead(KErrCancel);
+ iDatagramTail.Free();
+ break;
+ }
+ }
+ else
+ {
+ CompleteWrite(KErrCancel);
+ CompleteRead(KErrCancel);
+ h=MSessionControl::EImmediate;
+ }
+
+ CompleteConnect(KErrCancel);
+ CompleteSetLocalName(KErrCancel);
+
+ SetState(ESStateShuttingDown);
+
+ if(h!=MSessionControl::EImmediate)
+ {
+ SetBlockedClose();
+ DontCompleteCurrentRequest();
+ }
+
+ if (CanSendDisconnectData() && h!=MSessionControl::EImmediate && aDisconnectData)
+ {
+ TDes8& sendBuf = *BorrowTemporaryBufferL(iSendBufSize);
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(1),sendBuf);
+ iSSP->Shutdown(h,sendBuf);
+ }
+ else
+ {
+ iSSP->Shutdown(h);
+ }
+
+ if (iErrorOperationMask & MSessionControlNotify::EErrorClose)
+ {
+ SetReturn(iError);
+ ClearErrorIfNotFatal(); //Sets iError = 0;
+ iErrorOperationMask = 0;
+ }
+ // OK to access socket because a CanClose would set the socket state to dead
+ else if (h==MSessionControl::EImmediate)
+ {
+ // Set state to dead - let close delete the socket
+ SetState(ESStateDead);
+ }
+ else
+ {
+ if (!(iOptions & KOptBlocking) && IsBlockedClose())
+ {
+ CompleteClose(KErrWouldBlock);
+ }
+ }
+ }
+
+TBool ASocket::CloseSocket()
+/**
+A Client has closed our RSocket - or we're being closed by the session because our client has exited
+*/
+ {
+ SetClosing();
+ TBool immediateClose = EFalse;
+ switch (State())
+ {
+ case ESStateNull:
+ case ESStateAccepting:
+ case ESStateCreated:
+ case ESStateError:
+ case ESStateDead:
+ case ESStateDisconnected:
+ immediateClose = ETrue;
+ break;
+
+ case ESStateShuttingDown:
+ CompleteClose(KErrCancel);
+ SetReturn(KErrAlreadyExists);
+ SetState(ESStateClosing);
+ immediateClose = ETrue;
+ break;
+
+ case ESStateOpeningActive:
+ case ESStateOpeningPassive:
+ case ESStateOpen:
+ case ESStateConnected:
+ case ESStateBinding:
+ {
+ SetState(ESStateClosing);
+
+ TBool graceful = SupportsGracefulClose() && iSSP;
+ // CanClose will be called irrespective of whether the socket
+ // supports graceful close or not.
+ // ASocket can take care of the ownership of deletion via InitiateDestruction.
+ // Also, CanClose will call InitiateDestruction if we are in ESStateClosing.
+ // We already set to ESStateClosing.
+ SetBlockedClose();
+ DontCompleteCurrentRequest(); // Block closes regardless of NonBlocking mode state
+
+ if (graceful)
+ {
+ iSSP->Shutdown(MSessionControl::ENormal);
+ }
+ else
+ {
+ if (iSSP)
+ {
+ iSSP->Shutdown(MSessionControl::EImmediate);
+ }
+ CanClose(MSessionControlNotify::EDelete);
+ }
+ }
+ break;
+
+ case ESStateClosing:
+ PanicSocketClient(ECloseTwice);
+ break;
+ }
+ return immediateClose;
+ }
+
+void ASocket::BindL()
+/**
+Set local address from a client request.
+*/
+ {
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ if (IsConnectionOriented() && iIsBound)
+ {
+ SetReturn(KErrAlreadyExists);
+ }
+ else
+if (State() == ESStateBinding)
+ {
+ SetReturn(KErrInUse);
+ }
+ else
+ {
+ TSockAddr a;
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(0),a);
+
+
+ // Set to blocked before call to SetLocalName. This allows for immediate callback,
+ // as some conditions may not require asynchronous processing.
+ SetBlockedSetLocalName();
+ DontCompleteCurrentRequest();
+
+ // Save off the state for transition later.
+ iNextState = State();
+ SetState(ESStateBinding);
+
+ iSSP->SetLocalName(a);
+
+ }
+ }
+
+void ASocket::AutoBind()
+ {
+ iSSP->AutoBind();
+ iIsBound=ETrue;
+ }
+
+
+void ASocket::ConnectL(TBool aConnectData)
+/**
+Active open the socket - from a client request.
+*/
+ {
+ TSockAddr a;
+ TInt ret=KErrNone;
+ switch (State())
+ {
+ case ESStateOpeningActive:
+ case ESStateOpeningPassive:
+ PanicSocketClient(EConnectingAlready);
+ break;
+
+ case ESStateBinding:
+ SetReturn(KErrInUse);
+ break;
+
+ case ESStateConnected:
+ if (IsConnectionOriented())
+ {
+ if(IsBlockedConnect())
+ {
+ PanicSocketClient(EConnectingAlready);
+ }
+
+ SetReturn(KErrAlreadyExists);
+ return;
+ }
+ // Fall through - non connection oriented sockets can call Connect as much as they like.
+ case ESStateOpen:
+ case ESStateCreated:
+ {
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(0),a);
+
+ ret=iSSP->SetRemName(a);
+ if (ret!=KErrNone)
+ {
+ SetReturn(ret);
+ return;
+ }
+
+ if(!iIsBound)
+ {
+ SetBlockedConnect();
+ DontCompleteCurrentRequest();
+
+ if (!IsConnectionOriented())
+ {
+ iNextState = ESStateConnected;
+ }
+ else
+ {
+ iConnectData = aConnectData;
+ iNextState = ESStateOpeningActive;
+ }
+ SetState(ESStateBinding);
+ AutoBind();
+
+ if (!(iOptions&KOptBlocking) && IsBlockedConnect())
+ {
+ CompleteConnect(KErrWouldBlock);
+ }
+ return;
+
+ }
+
+ if (!IsConnectionOriented())
+ {
+ SetState(ESStateConnected);
+ TryToCompleteSelectIoctl();
+ }
+ else
+ {
+
+ SetBlockedConnect();
+ DontCompleteCurrentRequest();
+
+ SetState(ESStateOpeningActive);
+
+ if (CanSendConnectData() && aConnectData)
+ {
+ TDes8& sendBuf = *BorrowTemporaryBufferL(iSendBufSize);
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(1),sendBuf);
+ iSSP->ActiveOpen(sendBuf);
+ }
+ else
+ {
+ iSSP->ActiveOpen();
+ }
+
+ if (!(iOptions&KOptBlocking) && IsBlockedConnect())
+ {
+ CompleteConnect(KErrWouldBlock);
+ }
+ }
+ }
+ break;
+ case ESStateDisconnected:
+ case ESStateShuttingDown:
+ case ESStateClosing:
+ case ESStateDead:
+ SetReturn(KErrBadHandle);
+ break;
+ case ESStateError:
+ SetReturn(iError);
+ return;
+ default:
+ PanicSocketClient(ECannotConnect);
+ //Fault(EBadState);
+ break;
+ }
+
+ }
+
+//indexes of the data elements in RMessage for Get/SetOpt
+#define OPT_NAME_INDEX 0
+#define OPT_OPTION_INDEX 1 //for the option value
+#define OPT_OPT_LENGTH_INDEX 2
+#define OPT_OPT_LEVEL_INDEX 3
+
+/**
+ Set a socket option from a client request
+*/
+void ASocket::SetSockOptionL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel)
+ {
+
+ if (aOptionName & KSocketInternalOptionBit)
+ {
+ SetReturn(KErrAccessDenied);
+ return;
+ }
+
+ if (aOptionLevel==KSOLSocket)
+ {
+
+ TBufC8<sizeof(TUint)> smallOptionBuf;
+ TPtr8 option=smallOptionBuf.Des();
+
+ switch(aOptionName)
+ {
+ case KSOSendBuf:
+ {
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ iSendBufSize=*(TUint*)smallOptionBuf.Ptr();
+
+ // Even though we don't respect the sendbuf size for transfers we need to
+ // be able to echo the value back to a GetOpt() - also it's used for
+ // sizing the Connect/Shutdown_WithData operations
+ if (iSendBufSize==KSocketBufSizeUndefined)
+ {
+ iSendBufSize=KSocketDefaultBufferSize;
+ iOptions&=~KOptSendBufSet;
+ break;
+ }
+
+ iOptions|=KOptSendBufSet;
+ break;
+ }
+ case KSORecvBuf:
+ {
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ iRecBufSize=*(TUint*)smallOptionBuf.Ptr();
+
+ // Even though we don't respect the recvbuf size for transfers we need to
+ // be able to echo the value back to a GetOpt()
+ if (iRecBufSize==KSocketBufSizeUndefined)
+ {
+ iOptions&=~KOptRecBufSet;
+ break;
+ }
+ iOptions|=KOptRecBufSet;
+ break;
+ }
+
+ case KSODebug:
+ {
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ TBool b;
+ TPtr8 p((TUint8*)&b,sizeof(iSendBufSize),sizeof(iSendBufSize));
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),p);
+ if(*(TBool*)option.Ptr())
+ {
+ iOptions|=KOptDebug;
+ }
+ else
+ {
+ iOptions&=~KOptDebug;
+ }
+ break;
+ }
+ case KSONonBlockingIO:
+ iOptions &= ~KOptBlocking;
+ break;
+ case KSOBlockingIO:
+ iOptions |= KOptBlocking;
+ break;
+
+ //-- enable socket transfer to another process with capabilities check.
+ //-- socket option must be TPckgBuf<TSecurityPolicy>, TSecurityPolicy in turn must contain the capabilities set for the
+ //-- process that is going to receive this socket as a result of RSocket::Transfer().
+ case KSOEnableTransfer:
+ {
+ if(State() == ESStateNull || State() == ESStateAccepting)
+ {
+ User::Leave(KErrNotReady);
+ }
+ //-- read security information (capabilities set) from the client
+ TSecurityPolicyBuf secPolicyBuf;
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),secPolicyBuf);
+
+ //-- store the capabilities set for the future check in ProtocolManager::TransferSocketL()
+ iSecTransferEnabled=EFalse;
+ User::LeaveIfError(iTransferSecPolicy.Set(secPolicyBuf));
+ iSecTransferEnabled=ETrue; //-- indication that the RSocket::Transfer() security information is ready to check
+ }
+ break;
+
+ //-- Disable socket transfer by indicating that the transfer security information is not valid
+ case KSODisableTransfer:
+ iSecTransferEnabled=EFalse;
+ break;
+
+
+ default:
+ SetReturn(KErrNotSupported);
+ }
+ }
+ else
+ {
+ if (CheckRunningAndSetReturn())
+ {
+ HBufC8* optionBuf=NULL;
+ optionBuf=HBufC8::NewMaxLC(aOptionLength);
+ TPtr8 option=optionBuf->Des();
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ SetReturn(iSSP->SetOption(aOptionLevel,aOptionName,option));
+ CleanupStack::PopAndDestroy(optionBuf);
+ }
+ }
+ }
+
+void ASocket::GetSockOptionL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel, TInt aWriteBack)
+/**
+Read a socket option from us (or attempt the protocol if we don't support the option)
+
+*/
+ {
+
+ if (aOptionName&KSocketInternalOptionBit)
+ {
+ SetReturn(KErrAccessDenied);
+ return;
+ }
+ if (aOptionLevel==KSOLSocket)
+ {
+ // Most KSOLSocket options use argument1 as an out parameter
+ switch(aOptionName)
+ {
+ case KSOSendBuf:
+ case KSORecvBuf:
+ case KSODebug:
+ case KSONonBlockingIO:
+ case KSOBlockingIO:
+ case KSOSelectPoll:
+ {
+ if(aWriteBack)
+ {
+ // Retrieve the required value
+ TUint optionVal;
+ switch(aOptionName)
+ {
+ case KSOSendBuf:
+ {
+ optionVal =iSendBufSize;
+ break;
+ }
+ case KSORecvBuf:
+ {
+ optionVal =iRecBufSize;
+ break;
+ }
+ case KSODebug:
+ {
+ optionVal =(iOptions&KOptDebug);
+ break;
+ }
+ case KSONonBlockingIO:
+ {
+ optionVal =!(iOptions&KOptBlocking);
+ break;
+ }
+ case KSOBlockingIO:
+ {
+ optionVal =iOptions&KOptBlocking;
+ break;
+ }
+ case KSOSelectPoll:
+ {
+ if(CheckRunningAndSetReturn())
+ {
+ optionVal =SelectConditionsReady();
+ }
+ else
+ {
+ aWriteBack = EFalse;
+ }
+ break;
+ }
+ // coverity [dead_error_begin] :
+ default:
+ // the default should never be called and is there to catch coding errors.
+ __ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 5));
+ }
+ if(aWriteBack)
+ {
+ TPckg <TUint> option(optionVal);
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ }
+ }
+ else
+ {
+ // Somehow they passed a NULL second argument - should we panic them?
+ SetReturn(KErrArgument);
+ }
+
+ break;
+ }
+ case KSOSelectLastError:
+ {
+ SetReturn(iError);
+
+ if(aWriteBack)
+ {
+ TPckg <TUint> option(iError);
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ }
+ else
+ {
+ // Somehow they passed a NULL second argument - should we panic them?
+ SetReturn(KErrArgument);
+ }
+
+ ClearErrorIfNotFatal();
+ break;
+ }
+
+ case KSOReadBytesPending:
+ case KSOUrgentDataOffset:
+ {
+ if(!CheckRunningAndSetReturn())
+ {
+ break;
+ }
+
+ if(aOptionName==((TInt)KSOUrgentDataOffset) && !CanSendUrgentData())
+ {
+ SetReturn(KErrNotSupported);
+ break;
+ }
+ TSockXfrLength len;
+ len()=iRecOffset;
+ SetReturn(iSSP->GetOption(aOptionLevel,aOptionName,len));
+ if (aWriteBack)
+ {
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),len);
+ }
+ break;
+ }
+ default:
+ SetReturn(KErrNotSupported);
+ }
+ }
+
+ else
+ {
+ if(CheckRunningAndSetReturn())
+ {
+ if (aWriteBack)
+ {
+ RBuf8 optionBuf;
+ optionBuf.CreateMaxL(aOptionLength);
+ CleanupClosePushL(optionBuf);
+ TPtr8 option=optionBuf.MidTPtr(0);
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ SetReturn(iSSP->GetOption(aOptionLevel,aOptionName,option));
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+ CleanupStack::PopAndDestroy(&optionBuf);
+ }
+ else
+ {
+ SetReturn(KErrArgument);
+ }
+ }
+ }
+ }
+
+void ASocket::IoctlL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel, TBool aReadOption)
+/**
+Perform an Ioctl from a user request
+*/
+ {
+
+ if (IsBlockedIoctl())
+ {
+ PanicSocketClient(ETwoIoctls);
+ return;
+ }
+
+ if (aOptionName&KInternalIoctlBit)
+ {
+ SetReturn(KErrAccessDenied);
+ return;
+ }
+
+ if (aOptionLevel==KSOLSocket)
+ {
+
+ if(aOptionName==(TInt)KIOctlSelect)
+ {
+
+ if(!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+ TPckgBuf<TUint> flags;
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(1), flags);
+ iSelectFlags=flags();
+ if((iSelectFlags&KAllSelectFlags)!=0)
+ {
+ SetBlockedIoctl();
+ DontCompleteCurrentRequest();
+ TryToCompleteSelectIoctl();
+ }
+ else
+ {
+ SetReturn(KErrArgument);
+ }
+ }
+ else
+ {
+ SetReturn(KErrNotSupported);
+ }
+ }
+ else
+ {
+// if(!(iOptions & KOptBlocking))
+// {
+// SetReturn(KErrWouldBlock);
+// return;
+// }
+
+// if (CheckRunningAndSetReturn()==EFalse)
+// return;
+ if(iSSP == NULL)
+ {
+ SetReturn(KErrNotSupported);
+ return;
+ }
+
+ if (aReadOption)
+ {
+ if(aOptionLength < 0)
+ {
+ User::Leave(aOptionLength);
+ }
+ HBufC8* ioctlBuf=HBufC8::NewLC(aOptionLength);
+ TPtr8 des=ioctlBuf->Des();
+ ReadParamL(ESocketCurrentMessage,MSG_PRM(1),des);
+ // only set ioctl blocked if successfull allocation
+ SetBlockedIoctl();
+ DontCompleteCurrentRequest();
+
+ iSSP->Ioctl(aOptionLevel,aOptionName,&des);
+ CleanupStack::PopAndDestroy(ioctlBuf);
+ }
+ else
+ {
+ SetBlockedIoctl();
+ DontCompleteCurrentRequest();
+ iSSP->Ioctl(aOptionLevel,aOptionName,NULL);
+ }
+ }
+ LOG(
+ if (IsBlockedIoctl())
+ {
+ ESockLog::Printf(KESockSessDetailTag, _L8("ASocket::IoctlL blocking") );
+ }
+ )
+ }
+
+void ASocket::CancelIoctl()
+/**
+Cancel a pending Ioctl and notify the protocol.
+*/
+ {
+ if(IsBlockedIoctl())
+ {
+ TInt optionLevel = 0;
+ TInt optionName = 0;
+ if(!iSelectFlags)
+ {
+ optionLevel = iBlockedIoctlMsg->ReadInt(2);
+ optionName = iBlockedIoctlMsg->ReadInt(0);
+ }
+
+ CompleteIoctl(KErrCancel);
+
+ if(iSelectFlags)
+ {
+ iSelectFlags=0;
+ }
+ else
+ {
+ __ASSERT_ALWAYS(iSSP!=NULL, Panic(ENullSap));
+ iSSP->CancelIoctl(optionLevel, optionName);
+ }
+ }
+ }
+
+void ASocket::GetDisconnectDataL( ) const
+/**
+Get disconnect data if any is present on the socket.
+*/
+ {
+ if (CanSendDisconnectData())
+ {
+ if(iDisconnectDataError!=KErrNone)
+ {
+ SetReturn(iDisconnectDataError);
+ }
+ else if (iDisconnectData)
+ {
+ TPtr8 des=iDisconnectData->Des();
+ const_cast<ASocket*>(this)->WriteParamL(ESocketCurrentMessage,MSG_PRM(0),des);
+ }
+ else
+ {
+ SetReturn(KErrNotFound);
+ }
+ }
+ else
+ {
+ SetReturn(KErrNotSupported);
+ }
+ }
+
+static const TInt KPaddingForHeaders = 48;
+
+void ASocket::SendL(TInt aXferLenArg, TInt aAddrArg, TInt aSendByteCount, TInt aSendFlags, TBool aUseMBufs)
+/**
+ Common message service for Send, SendTo and Write.
+*/
+ {
+ if (IsBlockedWrite())
+ {
+ PanicSocketClient(EWritingAlready);
+ return;
+ }
+
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ // Judge If the socket is connected during a connection-oriented service.
+ if (IsConnectionOriented() && iState != ESStateConnected)
+ {
+ LOG( ESockLog::Printf(_L("ASocket %08x SendL() KErrNotReady"), this ) );
+ SetReturn(KErrNotReady);
+ return;
+ }
+
+ if(iBlockedOperations & EWriteStopped)
+ {
+ if(aXferLenArg >= 0)
+ {
+ iXferLength() = 0;
+ WriteParamL(ESocketCurrentMessage, aXferLenArg, iXferLength);
+ }
+ SetReturn(KErrEof);
+ return;
+ }
+
+ // Set whether we are sending RMbufChain or not
+ iSendUseMBufs = aUseMBufs;
+
+ iSendByteCount=aSendByteCount;
+ iSendXferLenIdx = aXferLenArg;
+ iSendToAddrIdx = aAddrArg;
+ if (iSendToAddrIdx >= 0)
+ {
+ if(IsConnectionOriented())
+ {
+ PanicSocketClient(ECantSendToOnConnection);
+ return;
+ }
+ }
+ else // Not ESendTo...
+ {
+ if(State() != ESStateConnected && State() != ESStateShuttingDown && iSendToAddrIdx != ASocket::KWriteNoAddrArg)
+ {
+ LOG( ESockLog::Printf(_L("ASocket %08x SendL() 2 KErrNotReady"), this ) );
+ SetReturn(KErrNotReady);
+ return;
+ }
+ }
+ iSendFlags = aSendFlags;
+ if(iSendFlags)
+ {
+ if(iSendFlags&KSocketInternalWriteBit)
+ {
+ SetReturn(KErrAccessDenied);
+ return;
+ }
+ if ((iSendFlags&KSockWriteUrgent) && !CanSendUrgentData())
+ {
+ SetReturn(KErrNotSupported);
+ return;
+ }
+ }
+ __ASSERT_DEBUG(iSendData.IsEmpty(), Fault(EBufsLeftInSendData)); // no pathway should leave this populated after Write completes
+ iSendData.Free(); // but paranoia is cheap
+
+ if(iSendByteCount<0)
+ {
+ PanicSocketClient(EBadDescriptorLength);
+ return;
+ }
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ IncludePerformanceData(-1, -1, iSendByteCount);
+#endif
+
+ if (iIsBound==EFalse)
+ {
+
+ if (State() == ESStateBinding)
+ {
+ SetReturn(KErrInUse);
+ return;
+ }
+ AutoBind();
+ }
+ iSendOffset=0;
+ DoSend(ETrue);
+ }
+
+void ASocket::DoSend(TBool aInitialRequest)
+ {
+ AMessage* msg = aInitialRequest? iCurrentMsg: iWriteMsg;
+ ASSERT(msg);
+
+ TInt ret = KErrNone;
+ TBool completeReq = ETrue;
+
+ if (IsStream())
+ {
+ ret = FillStreamProtocol(msg);
+
+ if(iSendByteCount > 0)
+ {
+ // Still data to write - flow-off or error
+ if(ret != KErrNone)
+ {
+ if(ret == KErrNoMBufs)
+ {
+ ret = RequestAsyncMBufAllocation(CWaitForMBufs::ECanSend, iSendByteCount);
+ }
+ if(ret != KErrNone)
+ {
+ ret = KErrNoMemory;
+ }
+ }
+ if(ret == KErrNone && (iOptions & KOptBlocking))
+ {
+ completeReq = EFalse;
+ }
+ }
+ }
+ else // !IsStream()
+ {
+ if (aInitialRequest && ((iProtocolInfo->iMessageSize!=KSocketMessageSizeNoLimit) && (iProtocolInfo->iMessageSize!=KSocketMessageSizeUndefined) && (iSendByteCount>iProtocolInfo->iMessageSize)) ||
+ ((iOptions&KOptSendBufSet) && iSendByteCount>iSendBufSize))
+ {
+ SetReturn(KErrTooBig);
+ return;
+ }
+
+ RMBufChain data;
+ TInt nwr = KErrNone;
+ TInt actualSendLen = 0; // total size of data accepted by protocol upon datagram write
+ TInt actualBufSize = 0;
+ if(aInitialRequest || iSendData.IsEmpty())
+ {
+ if (iSendUseMBufs)
+ {
+ ret = msg->ReadMBuf(MSG_PRM(2),data);
+ actualSendLen = data.Length();
+ actualBufSize = data.First()->Size();
+ }
+ else
+ {
+ // Possible outcomes:
+ // (1) We fail to create the MBuf chain with the client data:
+ // (a) with KErrNoMbufs - we start an asynchronous allocation and treat it as a flow-off
+ // (b) with some other -ve error code - we treat this as KErrNoMemory and complete the client
+ // (2) SAP fails to write the mbuf chain:
+ // (a) with KErrNoMbufs - we start an asynchronous allocation on its behalf and treat it as a flow-off
+ // (b) with zero, ie flow-off: we don't complete client
+ // (c) with some other -ve error code - we treat this as KErrNoMemory and complete the client
+ // (3) SAP write succeeds and returns > 1 - we complete the client with KErrNone
+ // get MBuf chain immediately, copy avoiding iSendBuf if possible
+
+ ret = data.Alloc(iSendByteCount + KPaddingForHeaders, iAllocator);
+ if(ret == KErrNone)
+ {
+ RMBuf* first = data.First();
+ if(first->Size() >= (iSendByteCount + KPaddingForHeaders))
+ {
+ // Read directly into buffer
+ first->SetData(KPaddingForHeaders, iSendByteCount);
+ TPtr8 des(NULL, 0);
+ des.Set(first->Ptr(), iSendByteCount, iSendByteCount);
+ ret = msg->ReadDes(MSG_PRM(2),des);
+ actualSendLen = des.Length();
+ actualBufSize = actualSendLen;
+ }
+ else
+ {
+ // Have to use local descriptor to avoid multiple IPC round trips
+ TDes8* sendBuf = BorrowTemporaryBuffer(iSendByteCount);
+ if(!sendBuf)
+ {
+ // We can't allocate a buffer as big as the client so risk losing data
+ // they've indicated as precious if it overflows. Failing immediately
+ // without trying is the compatible option
+ ret = KErrNoMemory;
+ }
+ else
+ {
+ if(first->Length() > KPaddingForHeaders)
+ {
+ first->AdjustStart(KPaddingForHeaders);
+ }
+ else
+ {
+ data.TrimStart(KPaddingForHeaders);
+ }
+ ret = msg->ReadDes(MSG_PRM(2), *sendBuf); // read failure exceedingly rare so don't bother checking return yet
+ actualSendLen = sendBuf->Length();
+ actualBufSize = actualSendLen;
+ data.CopyIn(*sendBuf);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Resume with the RMBufChain we already fabricated
+ data.Assign(iSendData);
+ if (iSendUseMBufs)
+ {
+ actualSendLen = data.Length();
+ actualBufSize = data.First()->Size();
+ }
+ else
+ {
+ actualSendLen = data.Length();
+ actualBufSize = actualSendLen;
+ }
+ }
+
+ if (ret == KErrNone)
+ {
+ // Clear the error operation mask. If a protocol errors the socket whilst in the
+ // context of the CServProviderBase::Write(...) down call, we will see it below.
+ iErrorOperationMask = 0;
+ if (iSendToAddrIdx < 0)
+ {
+ nwr = iSSPData->Write(data, iSendFlags, NULL);
+ }
+ else
+ {
+ TSockAddr addr;
+ ret = msg->ReadDes(iSendToAddrIdx, addr);
+ if(ret == KErrNone)
+ {
+ nwr = iSSPData->Write(data, iSendFlags, &addr);
+ }
+ }
+
+ if (nwr == 0)
+ {
+ // Flow unable to accept data but not erroring
+ completeReq = EFalse;
+ iSendData.Assign(data);
+ }
+
+ if (iErrorOperationMask & (MSessionControlNotify::EErrorSend))
+ {
+ // Protocol has errored the socket. Complete the current operation with the error.
+ // If the error is not fatal, then it is assumed to be for the current operation only,
+ // so clear down the error.
+ nwr = iError;
+ completeReq = ETrue;
+ ClearErrorIfNotFatal(); //Sets iError = 0;
+ iErrorOperationMask = 0;
+ iSendData.Free();
+ }
+
+ if(nwr < 0)
+ {
+ ret = nwr;
+ }
+ else if(iSendXferLenIdx >= 0)
+ {
+ iSendOffset = actualSendLen - data.Length();
+ }
+ if (!iSendUseMBufs)
+ {
+ // nwr > 0 == Sending using RMBufChain where we have to ensure the data is
+ // freed once the Send is succeeded
+ // Protocols must remove buffers they want to use
+ data.Free();
+ }
+ else
+ {
+ if (nwr > 0)
+ {
+ msg->InitMBuf(MSG_PRM(2));
+ }
+ }
+ }
+ if(ret != KErrNone)
+ {
+ if(ret == KErrNoMBufs)
+ {
+ ret = RequestAsyncMBufAllocation(CWaitForMBufs::ECanSend, actualBufSize);
+ if(ret != KErrNone)
+ {
+ ret = KErrNoMemory;
+ }
+ }
+ if(ret == KErrNone)
+ {
+ if(iOptions & KOptBlocking)
+ {
+ completeReq = EFalse;
+ }
+ else
+ {
+ ret = KErrWouldBlock;
+ }
+ }
+ }
+ }
+
+ if(completeReq)
+ {
+ // Write completed
+ if(iSendXferLenIdx >= 0)
+ {
+ iXferLength() = iSendOffset;
+ TInt lenRet = msg->WriteDes(iSendXferLenIdx, iXferLength);
+ if(lenRet != KErrNone && ret == KErrNone)
+ {
+ ret = lenRet;
+ }
+ }
+ // KErrBadDescriptor means that the client has already been panicked; we must
+ // avoid further completion of this message
+ if(ret == KErrBadDescriptor)
+ {
+ iBlockedOperations&=~EBlockedWrite;
+ }
+ else
+ {
+ if(aInitialRequest)
+ {
+ SetReturn(ret);
+ }
+ else
+ {
+ CompleteWrite(ret);
+ }
+ }
+ }
+ else
+ {
+ if(aInitialRequest)
+ {
+ // Doesn't matter if the client has already been panicked; we're acquiring the now-NULL msg
+ iWriteMsg->AcquireMessage(msg);
+ SetBlockedWrite();
+ iBlockedOperations|=EWriteFlowedOff;
+ DontCompleteCurrentRequest();
+ }
+ }
+ }
+
+void ASocket::RecvL(TInt aXferLenArg, TInt aAddrArg, TInt aReadByteCount, TInt aReadFlags, TBool aUseMBufs, TInt aRecvOneOrMore)
+/**
+ Common service routine from Recv, RecvFrom and Read.
+*/
+ {
+ if (IsBlockedRead())
+ {
+ PanicSocketClient(EReadingAlready);
+ return;
+ }
+
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ if (IsConnectionOriented())
+ {
+ if (State()!=ESStateConnected && State()!=ESStateShuttingDown)
+ {
+ LOG( ESockLog::Printf(_L("ASocket %08x RecvL() KErrNotReady"), this ) );
+ SetReturn(KErrNotReady);
+ return;
+ }
+ if (iIsBound==EFalse)
+ {
+ if (State() == ESStateBinding)
+ {
+ SetReturn(KErrInUse);
+ return;
+ }
+ AutoBind();
+ }
+ if (aAddrArg >= 0)
+ {
+ SetReturn(KErrNotSupported);
+ return;
+ }
+ }
+
+ iRecvOneOrMore = aRecvOneOrMore;
+ if(iRecvOneOrMore && !IsStream())
+ {
+ SetReturn(KErrNotSupported);
+ return;
+ }
+
+ // Set whether we are going to receive in RMBufChain way
+ iRecvUseMBufs = aUseMBufs;
+
+ iRecByteCount=aReadByteCount;
+ if(iRecByteCount<0)
+ {
+ PanicSocketClient(EBadDescriptorLength);
+ User::Leave(KErrBadDescriptor);
+ }
+ iRecvFlags=aReadFlags;
+ if(iRecvFlags)
+ {
+ if(iRecvFlags&KSocketInternalReadBit)
+ {
+ SetReturn(KErrAccessDenied);
+ return;
+ }
+ if (iRecvFlags&KSockReadPeek && !SupportsPeek())
+ {
+ SetReturn(KErrNotSupported);
+ return;
+ }
+ }
+ iRecvFromAddrIdx = aAddrArg;
+ iRecvXferLenIdx=aXferLenArg;
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ IncludePerformanceData(-1, iRecByteCount, -1);
+#endif
+
+ iRecOffset=0;
+ DoRecv(ETrue);
+ }
+
+void ASocket::DoRecv(TBool aInitialRequest)
+ {
+ AMessage* msg = aInitialRequest? iCurrentMsg: iReadMsg;
+
+ if(aInitialRequest || IsBlockedRead())
+ {
+ TInt errReadProtocol = KErrNone;
+ TBool completeReq = ETrue;
+
+ if((iBlockedOperations&EReadStopped) && iDataAvailable<=0)
+ {
+ TInt ret = msg->WriteDes(MSG_PRM(2), KNullDesC8);
+ iRecOffset = 0;
+ errReadProtocol = KErrEof;
+ }
+ else if (IsStream())
+ {
+ errReadProtocol = DrainStreamProtocol(msg);
+ if(errReadProtocol == KErrNone)
+ {
+ if(iRecvOneOrMore && iRecOffset > 0) // i.e. data received
+ {
+ iRecByteCount=0;
+ }
+ if (iRecByteCount>0) // Still data expected
+ {
+ if(!(iBlockedOperations&EReadStopped) || iDataAvailable>0)
+ {
+ if ((iOptions&KOptBlocking))
+ {
+ // This error condition can never be reached under the current structure. Further investigation into how other teams,
+ // such as Bluetooth, handle memory errors in this situation is needed before restructuring this method.
+
+ //if(errReadProtocol == KErrNoMBufs)
+ // {
+ // // Block unless request fails
+ // errReadProtocol = RequestAsyncMBufAllocation(CWaitForMBufs::ENewData, iRecByteCount/*iRecBuf.MaxLength()*/) == KErrNone;
+ // completeReq = errReadProtocol == KErrNone;
+ // }
+ //else
+ if(iError != KErrNone)
+ {
+ // Don't block as protocol is already erroring client
+ errReadProtocol = iError;
+ // If the socket error is not fatal, then reset it so that only the current
+ // receive operation is completed with the error (not every subsequent one).
+ ClearErrorIfNotFatal();
+ }
+ else
+ {
+ completeReq = EFalse;
+ }
+ }
+ else
+ {
+ errReadProtocol = KErrWouldBlock;
+ }
+ }
+ else
+ {
+ errReadProtocol = KErrEof;
+ }
+ }
+ }
+ }
+ else
+ { // !IsStream()
+
+ // If the previous call to Recv used the KSockReadContinuation method and left iDatagramTail empty (everything
+ // up to the end of the packet was read) then tailContinuation will be false this time round - this will cause
+ // the reading of new data from iSSP below.
+ TBool tailContinuation = (iRecvFlags & KSockReadContinuation) != 0 && !iDatagramTail.IsEmpty();
+ TBool needToBlock = !tailContinuation && iDataAvailable <= 0;
+ errReadProtocol = KErrNone;
+
+ if(aInitialRequest)
+ {
+ //-- if we have a read from the socket with flag KSockReadPeek set
+ //-- and if we need to block, set the NewData() recursion counter to 1.
+ //-- otherwise, reset it, it will not be checked then.
+ if(needToBlock && (iRecvFlags & KSockReadPeek))
+ {
+ iBlockOnPeekReadCnt = 1;
+ }
+ else
+ {
+ iBlockOnPeekReadCnt = 0;
+ }
+ }
+
+ if (!needToBlock)
+ {
+ TDes8* recBuf = BorrowTemporaryBuffer(iRecByteCount);
+ if(!recBuf)
+ {
+ // We can't allocate a buffer as big as the client so risk losing data
+ // they've indicated as precious if it overflows. Failing immediately
+ // without trying is the compatible option
+ errReadProtocol = KErrNoMemory;
+ }
+ // Only read from the provider if we can't use the previous tail
+ else if(!tailContinuation)
+ {
+ // Free it only if the chain is empty. For RMBufChain read, the receiveer must have been freed it.
+ // and we don't need to free it
+ if(!iDatagramTail.IsEmpty() && !iRecvUseMBufs)
+ {
+ iDatagramTail.Free();
+ }
+ if (iRecvFromAddrIdx < 0)
+ {
+ errReadProtocol = iSSPData->GetData(iDatagramTail, iRecByteCount | KGetDataWholeDatagram, iRecvFlags);
+ }
+ else
+ {
+ errReadProtocol = iSSPData->GetData(iDatagramTail, iRecByteCount | KGetDataWholeDatagram, iRecvFlags, &iRecvFromAddr);
+ }
+ }
+ // Protocols must either deliver the request or return an error and deliver nothing
+ //__ASSERT_DEBUG( (errReadProtocol < 0 && data.IsEmpty()), Panic(EBadDataCount));
+ TInt trimTailAmount = 0;
+ if(errReadProtocol < 0)
+ {
+ // Protocol has failed to deliver, so we'll have to block. If it's a KErrNoMBufs (a likely case) then we kick off
+ // an asynch allocation for amount and upon its completion try again. Of course we cannot know whether this is the
+ // number of mbufs that the protocol wanted but it's a good guess. If it's some other error then it's up to the
+ // protocol to tell us when to retry (by signalling with NewData(0)). If it was some error that the protocol
+ // couldn't handle at all then it should have set the error upon the socket rather than expecting us to magically
+ // "do the right thing"
+ needToBlock = ETrue;
+ }
+ else
+ {
+ if (iRecvUseMBufs)
+ {
+ // We don't trim anything, when we do a RMBufChain read with KSockReadPeek is set
+ // KSockReadPeek is upto the SAP shim
+ errReadProtocol = msg->WriteMBuf(MSG_PRM(2),iDatagramTail);
+ if(errReadProtocol == KErrNone)
+ {
+ iDatagramTail.Init();
+ // Just remove the chain that we have given back from the tail. When using MBufs the
+ // client always gets the entire datagram anyway (the datagram tail mechanism is there
+ // just so someone using a descriptor can do a continuation read if it overflows, so they
+ // don't have to use 64k buffer just in case some loony soaks them with a jumbogram).
+ // So there's no trimming done & no need to discriminate between peek & normal.
+ }
+ }
+ else
+ {
+ TPtr8 des(recBuf->MidTPtr(0, iRecByteCount));
+
+ if (!iDatagramTail.IsEmpty())
+ {
+ // intermediate descriptor copy
+ RMBuf* first = iDatagramTail.First();
+ if(!first->Next())
+ {
+ TInt copyLen = Min(first->Length(), iRecByteCount);
+ des.Set(first->Ptr(), copyLen, copyLen);
+ }
+ else
+ {
+ iDatagramTail.CopyOut(des, 0);
+ }
+ }
+ else
+ {
+ des.SetLength(0);
+ }
+ errReadProtocol = msg->WriteDes(MSG_PRM(2),des);
+ if((errReadProtocol == KErrNone && iRecvFlags & KSockReadPeek) == 0)
+ {
+ // Note the amount of data to trim after writing it to the client
+ trimTailAmount = des.Length();
+ }
+ }
+
+ #ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ IncludePerformanceData(trimTailAmount, -1, -1);
+ #endif
+
+ if(errReadProtocol == KErrNone)
+ {
+ if (trimTailAmount != 0)
+ {
+ iDatagramTail.TrimStart(trimTailAmount);
+ }
+ if(iRecvXferLenIdx >= 0)
+ {
+ // Number of bytes remaining. (store for later write)
+ iRecOffset = iDatagramTail.Length();
+ }
+ if(iRecvFromAddrIdx >= 0)
+ {
+ errReadProtocol = msg->WriteDes(iRecvFromAddrIdx, iRecvFromAddr);
+ }
+ if(errReadProtocol == KErrNone && !tailContinuation)
+ {
+ // When using a non-stream based socket the value iDataAvailable refers to the number of packets available.
+ // In the case where tail continuation is in use the packet may not fully have been dealt with yet (more
+ // could be read from it next time) and so the value should not be decremented yet. This is the case even
+ // if all the data up to the end of the packet has been read (the above call to TrimStart will leave
+ // iDatagramTail empty and then on the next call of this method tailContinuation will be set to false).
+ iDataAvailable--;
+ }
+ }
+ }
+ }
+
+ if(needToBlock)
+ {
+ if (iOptions & KOptBlocking)
+ {
+ if (errReadProtocol == KErrNoMBufs)
+ {
+ // Block unless request fails
+ needToBlock = RequestAsyncMBufAllocation(CWaitForMBufs::ENewData, iRecByteCount) == KErrNone;
+ }
+ else if (iError != KErrNone)
+ {
+ // Don't block as protocol is already erroring client
+ needToBlock = EFalse;
+ errReadProtocol = iError;
+ // If the socket error is not fatal, then reset it so that only the current
+ // receive operation is completed with the error (not every subsequent one).
+ ClearErrorIfNotFatal();
+ }
+ else if (errReadProtocol != KErrNone)
+ {
+ needToBlock = EFalse;
+ }
+ completeReq = !needToBlock;
+ }
+ else
+ {
+ errReadProtocol = KErrWouldBlock;
+ }
+ }
+ }
+
+ if(completeReq)
+ {
+ // Read completed
+ if(iRecvXferLenIdx >= 0)
+ {
+ iXferLength() = iRecOffset;
+ TInt ret = msg->WriteDes(iRecvXferLenIdx, iXferLength);
+ if(ret != KErrNone && errReadProtocol == KErrNone)
+ {
+ errReadProtocol = ret;
+ }
+ }
+ // KErrBadDescriptor means that the client has already been panicked; we must
+ // avoid further completion of this message
+ if(errReadProtocol == KErrBadDescriptor)
+ {
+ iBlockedOperations&=~EBlockedRead;
+ }
+ else
+ {
+ if(aInitialRequest)
+ {
+ SetReturn(errReadProtocol);
+ }
+ else
+ {
+ CompleteRead(errReadProtocol);
+ }
+ }
+ }
+ else
+ {
+ if(aInitialRequest)
+ {
+ // Doesn't matter if the client has already been panicked; we're acquiring the now-NULL msg
+ iReadMsg->AcquireMessage(msg);
+ SetBlockedRead();
+ DontCompleteCurrentRequest();
+ }
+ }
+ }
+ TryToCompleteSelectIoctl();
+ }
+
+void ASocket::ListenL(TInt aQlen, TBool aConnectionData)
+/**
+Listen request service
+Listen is a dead and, clients can't do anything with the socket other than Accept after a listen.
+*/
+ {
+
+ switch (State())
+ {
+ case ESStateConnected:
+ case ESStateOpeningActive:
+ case ESStateBinding:
+ SetReturn(KErrInUse);
+ return;
+ case ESStateOpeningPassive:
+ PanicSocketClient(EAlreadyListening);
+ //lint -fallthrough
+ case ESStateShuttingDown:
+ case ESStateClosing:
+ case ESStateDead:
+ SetReturn(KErrBadHandle);
+ return;
+ case ESStateDisconnected:
+ SetReturn(KErrDisconnected);
+ return;
+ case ESStateError:
+ SetReturn(iError);
+ return;
+ case ESStateNull:
+ case ESStateAccepting:
+ PanicSocketClient(ESockBadHandle);
+ return;
+ case ESStateCreated:
+ case ESStateOpen:
+ default:
+ break;
+ }
+
+ if (!IsConnectionOriented())
+ {
+ PanicSocketClient(EListenNeedsConnection);
+ return;
+ }
+
+ if (!iIsBound)
+ {
+ SetReturn(KErrBadName);
+ return;
+ }
+
+ if(!iAcceptQ)
+ {
+ iAcceptQ = new (ELeave) CCirBuf<TAcceptQEntry>;
+ }
+ CleanupStack::PushL(iAcceptQ);
+ iAcceptQ->SetLengthL(aQlen);
+
+ // Create a second queue we can transfer the contents to if we need to remove an SAP
+ // from the middle of the ring buffer.
+ if(!iNextAcceptQ)
+ {
+ iNextAcceptQ = new (ELeave) CCirBuf<TAcceptQEntry>;
+ }
+ CleanupStack::PushL(iNextAcceptQ);
+ iNextAcceptQ->SetLengthL(aQlen);
+
+ TInt ret;
+ if (aConnectionData)
+ {
+ TDes8& xferBuf = *BorrowTemporaryBufferL(iSendBufSize);
+ xferBuf.SetLength(iSendBufSize);
+ ReadParamL(ESocketCurrentMessage, MSG_PRM(1), xferBuf);
+ ret=iSSP->PassiveOpen(aQlen, xferBuf);
+ }
+ else
+ {
+ ret=iSSP->PassiveOpen(aQlen);
+ }
+
+ if (ret==KErrNone)
+ {
+ SetState(ESStateOpeningPassive);
+ }
+ else
+ {
+ SetReturn(ret);
+ }
+
+ CleanupStack::Pop(iNextAcceptQ);
+ CleanupStack::Pop(iAcceptQ);
+ }
+
+void ASocket::Accept()
+/**
+Accept a connection on a listening socket.
+*/
+ {
+
+ if ( State()!=ESStateOpeningPassive ) // protocol may have generated an error on the accept
+ { // SAP for some bizzare reason. We can't test just (State()==ESStateError)
+ // 'cos if reconnection iState could be whatever (see ASocket::Error)
+ //so check if we'r listenning at all
+ SetReturn(iError != KErrNone ? iError : KErrNotReady);
+ return;
+ }
+
+ if ( !iAcceptQ || !iNextAcceptQ )
+ {
+ PanicSocketClient(ENotListening);
+ return;
+ }
+
+ if (IsBlockedConnect())
+ {
+ PanicSocketClient(EAcceptTwice);
+ return;
+ }
+
+
+ ASocket* acceptingSocket = InitiateAcceptingSocket();
+
+ if ( !acceptingSocket ) // The acceptingSocket will be NULL if we got a panic. return here.
+ return;
+
+ if (!iAcceptQ->Count())
+ {
+ if (!(iOptions & KOptBlocking))
+ {
+ SetReturn(KErrWouldBlock);
+ return;
+ }
+
+ SetBlockedConnect();
+ DontCompleteCurrentRequest();
+ return;
+ }
+
+ // If the queue isn't empty setting the blocked connect and calling DoCompleteAccept will work it's magic - this saves us code
+ SetBlockedConnect();
+ DoCompleteAccept();
+ DontCompleteCurrentRequest(); // Don't want to complete twice.
+ }
+
+void ASocket::LocalNameL()
+/**
+Get local name for a client request
+*/
+ {
+
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ if (!iIsBound)
+ {
+ SetReturn(KErrNotFound);
+ return;
+ }
+ else
+ {
+ TSockAddr addr;
+ iSSP->LocalName(addr);
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(0),addr);
+ }
+
+ }
+
+void ASocket::RemoteNameL()
+/**
+Get remote name for a cleient request
+*/
+ {
+
+ if (!CheckRunningAndSetReturn())
+ {
+ return;
+ }
+
+ if (State()==ESStateConnected || State()==ESStateOpeningActive || State()==ESStateShuttingDown)
+ {
+ TSockAddr addr;
+ iSSP->RemName(addr);
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(0),addr);
+ }
+ else
+ {
+ SetReturn(KErrNotFound);
+ return;
+ }
+ }
+
+void ASocket::NewData(TUint aCount)
+/**
+Called from a protocol to indicate that new data is available for reading
+
+*/
+ {
+ __ASSERT_DEBUG(State()!=ESStateDead,Panic(EBadStateUpCall));
+// __ASSERT_DEBUG(State()!=ESStateCreated,Panic(EBadStateUpCall)); // no longer forced into shuttingdown state upon half-close
+ __ASSERT_DEBUG(State()!=ESStateClosing,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(!(iBlockedOperations&EReadStopped),Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateError,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateDisconnected,Panic(EBadStateUpCall));
+// zero is used in v1.5 to resume after reneging __ASSERT_DEBUG(aCount>0,Panic(EBadDataCount));
+
+ if(aCount==KNewDataEndofData)
+ {
+ iBlockedOperations |= EReadStopped;
+ }
+ else
+ {
+ iDataAvailable+=aCount;
+ __ASSERT_DEBUG(iDataAvailable>=0,Panic(EBadDataCount));
+ }
+
+ //-- check the recursion level counter.
+ //-- if it is 0, there were no recursion entry to itself, continue.
+ //-- if it is 1, there was blocked read from socket with KSockReadPeek set, increase it and continue.
+ //-- if it is 2, it means that function has been called from itself via NewData()-> [iSSP->CetData()] -> NewData()
+ //-- return to stop the infinite recursion.
+ if(iBlockOnPeekReadCnt >0)
+ {
+ if(iBlockOnPeekReadCnt >= 2)
+ {
+ iBlockOnPeekReadCnt = 0;
+ return;
+ }
+ else
+ {
+ iBlockOnPeekReadCnt ++;
+ }
+ }
+
+ DoRecv(EFalse);
+ }
+
+void ASocket::CanSend()
+/**
+Called from protocol to indicate new buffer space has become available
+*/
+ {
+ __ASSERT_DEBUG(State()!=ESStateDead,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateCreated,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateClosing,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateShuttingDown,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateError,Panic(EBadStateUpCall));
+ __ASSERT_DEBUG(State()!=ESStateDisconnected,Panic(EBadStateUpCall));
+
+ TBool writeflowedoff = iBlockedOperations&EWriteFlowedOff;
+ iBlockedOperations &= ~EWriteFlowedOff;
+ if(IsBlockedWrite())
+ {
+ DoSend(EFalse);
+ }
+ if(writeflowedoff && !(iBlockedOperations&EWriteFlowedOff))
+ {
+ TryToCompleteSelectIoctl();
+ }
+ }
+
+
+void ASocket::ConnectComplete()
+/**
+Called from protocol to indicate that an active open has completed
+*/
+ {
+ //__ASSERT_DEBUG(State()==ESStateOpeningActive,Panic(EBadStateUpCall));
+ if (IsConnectionOriented())
+ {
+ SetState(ESStateConnected);
+ //__ASSERT_DEBUG(IsBlockedConnect(), Panic(EUnexpectedConnect));
+ // assertion is invalid because operation could have been cancelled MarkT
+ CompleteConnect(KErrNone);
+ }
+ TryToCompleteSelectIoctl();
+ }
+
+void ASocket::ConnectComplete(const TDesC8& aConnectData)
+/**
+Called from protocol to indicate that an active open has completed with connection data
+*/
+ {
+ __ASSERT_ALWAYS(CanSendConnectData(),Panic(EUnexpectedConnectData));
+ //__ASSERT_DEBUG(IsBlockedConnect(),Panic(EUnexpectedConnect));
+ // assertion is invalid because operation could have been cancelled
+ if ( !iBlockedConnectMsg->IsNull (MSG_PRM(2)) )
+ {
+ TInt ret = iBlockedConnectMsg->WriteDes(MSG_PRM(2),aConnectData);
+ if(ret!= KErrNone)
+ {
+ return;
+ }
+ }
+ ConnectComplete();
+ }
+
+void ASocket::ConnectComplete(CSubConnectionFlowBase& anSSP)
+/**
+Called from protocol to indicate that a passive open has completed
+*/
+ {
+ __ASSERT_DEBUG(State()==ESStateOpeningPassive,Panic(EBadStateUpCall));
+ __ASSERT_ALWAYS(iAcceptQ, Panic(ENotListeningSocket));
+ __ASSERT_ALWAYS(iAcceptQ->Count()<iAcceptQ->Length(), Panic(EAcceptQueFull));
+
+ TAcceptQEntry n;
+ n.iSSP = &anSSP;
+ n.iConnectData=NULL;
+ n.iConnectDataError=KErrNone;
+ iAcceptQ->Add(&n);
+
+ DoCompleteAccept();
+ //LOG( ESockLog::Printf(_L("ASocket::ConnectComplete iAcceptQ->=%d, provider =%u)"), iAcceptQ->Count(), (void*)&anSSP ) );
+ TryToCompleteSelectIoctl();
+ }
+
+void ASocket::ConnectComplete(CSubConnectionFlowBase& anSSP,const TDesC8& aConnectData)
+/**
+Called from protocol to indicate that a passive open has completed with connection data
+*/
+ {
+ __ASSERT_ALWAYS(CanSendConnectData(),Panic(EUnexpectedConnectData));
+ __ASSERT_ALWAYS(iAcceptQ, Panic(ENotListeningSocket));
+ __ASSERT_ALWAYS(iAcceptQ->Count()<iAcceptQ->Length(), Panic(EAcceptQueFull));
+
+ TAcceptQEntry n;
+ n.iSSP = &anSSP;
+ n.iConnectDataError = KErrNone;
+ n.iConnectData=aConnectData.Alloc();
+ if(!n.iConnectData)
+ {
+ n.iConnectDataError = KErrNoMemory;
+ }
+ iAcceptQ->Add(&n);
+
+ DoCompleteAccept();
+ TryToCompleteSelectIoctl();
+ }
+
+void ASocket::DoCompleteAccept()
+/**
+Common dequeue for accept upcalls
+*/
+ {
+ __ASSERT_DEBUG(iAcceptQ->Count(),Fault(EBadAcceptQueue));
+
+ if (!IsBlockedConnect())
+ {
+ return;
+ }
+
+ TAcceptQEntry a;
+ iAcceptQ->Remove(&a);
+
+ ASocket* newCon=GetAcceptingSocket();
+ CTransportFlowShim* shimFlow = factoryobject_cast<CTransportFlowShim>(a.iSSP);
+ __ASSERT_DEBUG(shimFlow, User::Panic(KSpecAssert_ESockSSocksntsck, 6));
+
+ // The SAP is no longer owned by the listener socket.
+ shimFlow->iListenerControlNotify = NULL;
+
+ if (newCon == NULL)
+ {
+ // Delete the flow created for accept
+ shimFlow->InitDestroy();
+ CompleteConnect(KErrCancel);
+ return;
+ }
+
+ TRAPD(ret, newCon->AcceptSetupL(*this,*a.iSSP));
+ //!!!there was a defect where by deleting iSSP here the TCP PRT would crash. Steve Butler
+ //fixed it => check it snce aiSSP would be deleted had AcceptSetupL left!!!
+ if (ret != KErrNone)
+ {
+ CompleteConnect(ret);
+ return;
+ }
+/* goes into AcceptSetupL vitual fn
+ if (newCon->State()!=ESStateAccepting && newCon->State()!=ESStateNull)
+ {
+ //Session()->PanicSocketClient(iBlockedConnect,KESockClientPanic,EBadAccept);
+ CWorkerSession::PanicSocketClient(iBlockedConnect,KESockClientPanic,EBadAccept);
+ iSession->DontCompleteCurrentRequest();
+ return;
+ }
+*/
+ newCon->SetState(ESStateConnected);
+
+ if (a.iConnectData)// && iBlockedConnect.Ptr2()) checked in WriteParam
+ {
+ TPtr8 des=a.iConnectData->Des();
+ ret = iBlockedConnectMsg->WriteDes(MSG_PRM(2),des,0);
+ if(ret!= KErrNone)
+ {
+ return;
+ }
+ }
+
+ delete a.iConnectData;
+
+ // Call SecurityCheck() on the new SAP to communicate the MProvdSecurityChecker
+ // pointer to it. It is a somewhat bizarre situation if the PRT returns an error
+ // to this as, in reality, the PRT should not make a ConnectComplete() upcall in the
+ // first place only to fail the subsequent SecurityCheck() downcall. The PRT should check
+ // security beforehand and, on failure, simply not call ConnectComplete(). However, if we
+ // get an error, then complete the RSocket::Accept() operation on the listening socket with
+ // the error and place the accept socket in the error state.
+ ret = newCon->SecurityCheck();
+ if (ret != KErrNone)
+ {
+ LOG( ESockLog::Printf(_L("ASocket %08x:\tDoCompleteAccept(): socket %08x returned security check error %d"), this, a.iSSP, ret ) );
+ a.iConnectDataError = ret;
+ newCon->Error(ret, MSessionControlNotify::EErrorFatal);
+ }
+
+ newCon->iSSP->Start();
+ CompleteConnect(a.iConnectDataError);
+ }
+
+void ASocket::CanClose(MSessionControlNotify::TDelete aDelete)
+/**
+Called from protocol to indicate that a graceful close has completed
+*/
+ {
+ (void)aDelete;
+
+ //__ASSERT_ALWAYS(IsBlockedClose(),Panic(EUnexpectedClose));
+ // assertion is invalid because operation could have been cancelled MarkT
+ __ASSERT_DEBUG(State()==ESStateClosing||State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+ CompleteClose(KErrNone);
+ if (iFlowBinder)
+ {
+ iFlowBinder->Unbind();
+ }
+ // Flowbinder takes care of itself from now onwards; forget all downwards pointers
+ iSSP = NULL;
+ iSSPData = NULL;
+ iFlowBinder = NULL;
+ iServiceProvider.Close();
+/* Flow binder takes care of this SAP behaviour
+ if(aDelete==MSessionControlNotify::EDetach)
+ {
+ iSSP = NULL; // Stop d'tor deleting the SSP.
+ iFlowBinder = NULL;iSSPData = NULL;
+ }
+*/
+ if (State()==ESStateClosing)
+ {
+ SetState(ESStateDead);
+
+ // delete this; must not access member data after executing this statement
+ InitiateDestruction();
+ }
+ else
+ {
+ SetState(ESStateDead);
+ }
+
+ }
+
+void ASocket::CanClose(const TDesC8& aDisconnectData, MSessionControlNotify::TDelete aDelete)
+/**
+Called from protocol to indicate that a graceful close has completed with disconnect data
+*/
+ {
+
+ //__ASSERT_ALWAYS(IsBlockedClose(),Panic(EUnexpectedClose));
+ // assertion is invalid because operation could have been cancelled MarkT
+ // or could be non-blocking close
+ __ASSERT_ALWAYS(CanSendDisconnectData(),Panic(EUnexpectedDisconnectData));
+ TInt ret = iBlockedCloseMsg->WriteDes(MSG_PRM(2),aDisconnectData);
+ if(ret!= KErrNone)
+ {
+ return;
+ }
+ CanClose(aDelete);
+ }
+
+void ASocket::Disconnect()
+/**
+Called from protocol to indicate that a disconnect has been initiated - prob from the remote host
+*/
+ {
+ __ASSERT_ALWAYS(IsConnectionOriented(),Panic(EBadDisconnect));
+ __ASSERT_DEBUG(State()==ESStateConnected || State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+ iDisconnectDataError=KErrNone;
+
+ SetState(CanReconnect() ? ESStateCreated : ESStateDisconnected);
+ CompleteWrite(KErrDisconnected);
+ CompleteRead(KErrDisconnected);
+ CompleteConnect(KErrDisconnected);
+ TryToCompleteSelectIoctl();
+ }
+
+void ASocket::Disconnect(TDesC8& aDisconnectData)
+/**
+Called from protocol to indicate that a disconnect has been initiated - prob from the remote host - with disconnect data
+*/
+ {
+ __ASSERT_DEBUG(IsConnectionOriented(),Panic(EBadDisconnect));
+ __ASSERT_DEBUG(State()==ESStateConnected || State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+ Disconnect();
+ iDisconnectData=aDisconnectData.Alloc();
+ if(!iDisconnectData)
+ {
+ iDisconnectDataError = KErrNoMemory;
+ }
+ else
+ {
+ iDisconnectDataError = KErrNone;
+ }
+ }
+
+void ASocket::DisconnectFromListener(CSubConnectionFlowBase& aSSP)
+/**
+Called from protocol to indicate that a disconnect has been initiated for an SAP which has not been
+accepted yet and is waiting in the accept queue of a listening socket
+*/
+ {
+ #ifdef _DEBUG
+ TBool found = EFalse;
+ #endif
+
+ while(iAcceptQ->Count())
+ {
+ // Remove the entry from the old queue.
+ TAcceptQEntry a;
+ iAcceptQ->Remove(&a);
+
+ // Add it to the new queue if it is not the one we want to remove.
+ if(a.iSSP != &aSSP)
+ {
+ iNextAcceptQ->Add(&a);
+ }
+#ifdef _DEBUG
+ else
+ {
+ found = ETrue;
+ }
+#endif
+ }
+
+ // Swap the queues.
+ CCirBuf<TAcceptQEntry>* temp = iNextAcceptQ;
+ iNextAcceptQ = iAcceptQ;
+ iAcceptQ = temp;
+
+ __ASSERT_DEBUG(found,Panic(EBadDisconnectFromListener));
+ }
+
+void ASocket::IoctlComplete(TDesC8 *aBuf)
+/**
+Called from protocol to indicate that an outstanding ioctl has completes
+*/
+ {
+
+ if (aBuf && !iBlockedIoctlMsg->IsNull (MSG_PRM(1)))
+ {
+ TInt ret = iBlockedIoctlMsg->WriteDes(MSG_PRM(1),*aBuf);
+ if(ret!= KErrNone)
+ {
+ return;
+ }
+ }
+ CompleteIoctl(KErrNone);
+ }
+
+void ASocket::SetLocalNameComplete()
+/**
+Called from protocol to indicate that an outstanding Bind has completed
+*/
+ {
+ if (State() == ESStateBinding)
+ {
+ // A SetLocalName or Autobind had just completed.
+ SetState(iNextState); // Move to next state.
+ iIsBound=ETrue;
+
+ switch(iNextState)
+ {
+ case ESStateCreated:
+ case ESStateOpen:
+ CompleteSetLocalName(KErrNone);
+ break;
+ case ESStateConnected:
+ // UDP case
+ TryToCompleteSelectIoctl();
+ CompleteConnect(KErrNone);
+ break;
+ case ESStateOpeningActive:
+ if (CanSendConnectData() && iConnectData)
+ {
+ TDes8* sendBuf = BorrowTemporaryBuffer(KMaxStreamChunk);
+ TInt ret;
+ if(!sendBuf)
+ {
+ ret = KErrNoMemory;
+ }
+ else
+ {
+ ret = GetUserMessage(ESocketConnectMessage)->ReadDes(MSG_PRM(1), *sendBuf);
+ }
+ if (ret == KErrNone)
+ {
+ iSSP->ActiveOpen(*sendBuf);
+ }
+ else
+ {
+ CompleteConnect(ret);
+ }
+ }
+ else
+ {
+ iSSP->ActiveOpen();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+void ASocket::CancelConnect()
+ {
+ if (State()==ESStateDead)
+ {
+ PanicSocketClient(ESockBadHandle);
+ return;
+ }
+
+ CompleteConnect(KErrCancel);
+ iSSP->Shutdown(MSessionControl::EImmediate);
+
+ if (CanReconnect())
+ {
+ // Reset socket state
+ if (IsConnectionOriented())
+ {
+ SetState(ESStateCreated);
+ }
+ else
+ {
+ SetState(ESStateOpen);
+ }
+ }
+ else
+ {
+ SetState(ESStateError);
+ }
+
+ }
+
+void ASocket::CancelAccept()
+ {
+ CompleteConnect(KErrCancel);
+ }
+
+void ASocket::CancelAll()
+/**
+Cancel All pending requests
+
+*/
+ {
+ CancelIoctl();
+ CompleteWrite(KErrCancel);
+ CompleteRead(KErrCancel);
+ if (IsBlockedConnect())
+ {
+ if (State()==ESStateOpeningPassive)
+ {
+ CancelAccept();
+ }
+ else
+ {
+ CancelConnect();
+ }
+ }
+ CompleteClose(KErrCancel);
+ CompleteSetLocalName(KErrCancel);
+ }
+
+void ASocket::GetInfoL()
+/**
+Get protocol info for this socket
+
+*/
+ {
+ if (State()==ESStateNull || State()==ESStateAccepting)
+ {
+ SetReturn(KErrNotFound);
+ return;
+ }
+
+ __ASSERT_DEBUG(iProtocolInfo, User::Panic(KSpecAssert_ESockSSocksntsck, 7));
+ TPckg<TProtocolDesc> p(*iProtocolInfo);
+ WriteParamL(ESocketCurrentMessage,MSG_PRM(0),p,0);
+ }
+
+TInt ASocket::Error(TInt aError, TUint aOperationMask)
+/**
+Error up call from SSP, carries a bitmask indicating exactly which operations to signal the error on.
+*/
+ {
+#if defined(SYMBIAN_NETWORKING_LEGACY_COMPATIBILITY_SUPPORT)
+ // Support for the IP stack's just-in-time resetting of a shutdown socket's state is is provided by allowing it
+ // to notify via a pseudo-error. This is all in support of regrettable behaviour that after a shutdown TCP and UDP
+ // sockets must complete reads & writes with a different error code to all other sockets.
+ if(aOperationMask == MSessionControlNotify::EErrorLegacySupportRequest)
+ {
+ SetState((TSocketState) aError);
+ return KErrNone;
+ }
+#endif
+ if (aOperationMask == MSessionControlNotify::EErrorCompleteConnect)
+ {
+ CompleteConnect(aError);
+ }
+ else
+ {
+ DoError(aError, aOperationMask, ETrue);
+ }
+
+ return State() == ESStateError ? KErrGeneral : KErrNone;
+ }
+
+void ASocket::DoError(TInt aError, TUint aOperationMask, TBool /*aDeleteInterface*/)
+ {
+ __ASSERT_DEBUG(iState!=ESStateDead,Panic(EBadStateUpCall));
+// __ASSERT_DEBUG(iState!=ESStateError,Panic(EBadStateUpCall));
+ //__ASSERT_DEBUG(iState!=ESStateDisconnected,Panic(EBadStateUpCall));
+ //__ASSERT_DEBUG(anError!=KErrNone,Panic(EBadErrorCall));
+
+ // completionMask remembers whether there were any pending operations that were not completed,
+ // and whether the error is fatal (i.e. the socket permanently returns an error).
+ TUint completionMask = aOperationMask & MSessionControlNotify::EErrorFatal;
+ if (aOperationMask & MSessionControlNotify::EErrorClose)
+ {
+ if (!CompleteClose(aError))
+ {
+ completionMask |= MSessionControlNotify::EErrorClose;
+ }
+ }
+
+ if (aOperationMask & MSessionControlNotify::EErrorRecv)
+ {
+ if (!CompleteRead(aError))
+ {
+ completionMask |= MSessionControlNotify::EErrorRecv;
+ }
+ }
+
+ if (aOperationMask & MSessionControlNotify::EErrorSend)
+ {
+ if (!CompleteWrite(aError))
+ {
+ completionMask |= MSessionControlNotify::EErrorSend;
+ }
+ }
+
+ if ((aOperationMask&MSessionControlNotify::EErrorIoctl) && !iSelectFlags)
+ {
+ CompleteIoctl(aError);
+ }
+ if (aOperationMask & MSessionControlNotify::EErrorCompleteSetLocalName)
+ {
+ CompleteSetLocalName(aError);
+ }
+
+ iError = aError;
+ if (completionMask)
+ {
+ iErrorOperationMask = aOperationMask & completionMask;
+ }
+
+ if (State() == ESStateBinding && ((iNextState == ESStateCreated) || (iNextState == ESStateOpen)))
+ {
+ // If SetLocalName in progress then do not put the socket to
+ // a sticky error state.
+ iError = KErrNone;
+ // Reset socket state.
+ if (!IsConnectionOriented())
+ {
+ SetState(ESStateOpen);
+ }
+ else
+ {
+ SetState(ESStateCreated);
+ }
+ }
+ else
+
+ if (aOperationMask & MSessionControlNotify::EErrorConnect || aOperationMask&MSessionControlNotify::EErrorFatal)
+ {
+ CompleteConnect(aError);
+
+ // KErrNoMemory not treated as a fatal error
+ if (aError == KErrBindersInvalid || (!CanReconnect() && aError != KErrNoMemory))
+ {
+ // Fatal error
+ iError = aError;
+ SetState(ESStateError);
+ }
+ else
+ {
+ // Reset socket state
+ if (!IsConnectionOriented())
+ {
+ SetState(ESStateOpen);
+ }
+ else
+ {
+ SetState(ESStateCreated);
+ }
+ }
+ }
+
+ if (iError == KErrBindersInvalid)
+ {
+ __ASSERT_DEBUG(iFlowBinder, User::Panic(KSpecAssert_ESockSSocksntsck, 8));
+ iFlowBinder->Unbind();
+ iFlowBinder = NULL;
+ iSSP = NULL;
+ iSSPData = NULL;
+ iServiceProvider.Close();
+ }
+ TryToCompleteSelectIoctl();
+ }
+
+TInt ASocket::DrainStreamProtocol(AMessage* aMsg)
+/**
+ Drain a stream based protocol into client buffers.
+*/
+ {
+ __ASSERT_DEBUG(iDataAvailable>=0,Panic(EBadByteCount));
+ __ASSERT_DEBUG(iRecByteCount>=0,Panic(EBadByteCount));
+
+ TDes8* recBuf = NULL;
+ if(!iRecvUseMBufs)
+ {
+ TInt xferBufSize = Min((TInt) KMaxStreamChunk, Min(iDataAvailable, iRecByteCount));
+ recBuf = BorrowTemporaryBuffer(xferBufSize);
+ if(!recBuf)
+ {
+ return KErrNoMemory;
+ }
+ }
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ TInt rxActual = 0;
+#endif
+
+ RMBufChain data;
+ TInt ret = KErrNone;
+ do
+ {
+ TInt xfrLen;
+ if (iRecvUseMBufs)
+ {
+ // We are using RMBufChain. So we can read the complete data that is available
+ xfrLen = iDataAvailable;
+ }
+ else
+ {
+ xfrLen = Min(recBuf->MaxLength(), Min(iDataAvailable, iRecByteCount));
+ }
+
+ if (xfrLen==0)
+ {
+ return KErrNone;
+ }
+
+
+ RMBufChain data;
+ ret = iSSPData->GetData(data, xfrLen, iRecvFlags);
+ if (ret == 0 && iBlockedOperations&EReadStopped)
+ {
+ /* Look for the special case, where the SSP renegs on the amount of
+ * data available after an EStopInput Shutdown, as that can stop us
+ * ever exiting this while loop. */
+ iDataAvailable = 0;
+ return KErrEof;
+ }
+ if(ret >= 0)
+ {
+ // Now we received something.
+ if (iRecvUseMBufs)
+ {
+ ret = aMsg->WriteMBuf(MSG_PRM(2), data );
+ // No need to delete as the write operation has taken the ownership of our RMBufChain
+ }
+ else
+ {
+ // Default assumption is multi-buf chain
+ TPtr8 des(const_cast<TUint8*>(recBuf->Ptr()), xfrLen, xfrLen);
+ if(!data.First()->Next())
+ {
+ // Actually data is all in one buf; repoint descriptor at that
+ des.Set(data.First()->Ptr(), data.First()->Length(), data.First()->Length());
+ }
+ else
+ {
+ data.CopyOut(des, 0);
+ }
+ xfrLen = des.Length();
+ ret = aMsg->WriteDes(MSG_PRM(2), des, iRecOffset);
+ if ( ret == KErrNone )
+ {
+ data.Free(); // Free the chain
+ }
+ }
+ if(ret == KErrNone)
+ {
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ rxActual += ipcLen;
+#endif
+ iRecOffset += xfrLen;
+ iDataAvailable -= xfrLen;
+ iRecByteCount -= xfrLen;
+ }
+ }
+ else if(xfrLen <= 0)
+ {
+ // Failed to read or write on this iteration; we're done
+ break;
+ }
+ } while(ret == KErrNone);
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+ IncludePerformanceData(rxActual, -1, -1);
+#endif
+ return ret;
+ }
+
+TInt ASocket::FillStreamProtocol(AMessage* aMsg)
+/**
+ Fill a stream protocol from client buffers
+*/
+ {
+ __ASSERT_DEBUG(iSendByteCount>=0,Panic(EBadByteCount));
+ TPtr8 des(NULL, 0);
+ TDes8* sendBuf;
+ if(!iSendUseMBufs)
+ {
+ sendBuf = BorrowTemporaryBuffer(Min((TInt) KMaxStreamChunk, iSendByteCount));
+ if(!sendBuf)
+ {
+ return KErrNoMemory;
+ }
+ }
+ else
+ {
+ sendBuf = NULL;
+ }
+
+ RMBufChain data;
+ data.Assign(iSendData); // pick up any flowed-off chain
+ TInt xfrLen = data.Length();
+
+ do
+ {
+ TInt err = KErrNone;
+ if(data.IsEmpty())
+ {
+ // Need to pick up more data from client
+ if (!iSendUseMBufs)
+ {
+ xfrLen = Min(sendBuf->Size(), iSendByteCount);
+ err = data.Alloc(xfrLen, iAllocator);
+ if(err == KErrNone)
+ {
+ RMBuf* first = data.First();
+ if(first->Length() >= xfrLen)
+ {
+ des.Set(first->Ptr(), xfrLen, xfrLen);
+ err = aMsg->ReadDes(MSG_PRM(2),des, iSendOffset);
+ }
+ else
+ {
+ des.Set(const_cast<TUint8*>(sendBuf->Ptr()), xfrLen, xfrLen);
+ err = aMsg->ReadDes(MSG_PRM(2), des, iSendOffset);
+ data.CopyIn(des); // read failure exceedingly rare so don't bother checking return yet
+ }
+ if(err != KErrNone)
+ {
+ data.Free();
+ }
+ }
+ }
+ else
+ {
+ err = aMsg->ReadMBuf(MSG_PRM(2), data);
+ if(err == KErrNone)
+ {
+ xfrLen = data.Length();
+ }
+ }
+ }
+ else
+ {
+ xfrLen = data.Length();
+ }
+ if(err != KErrNone)
+ {
+ // Failed getting data from the client; bail now without further disturbing the state
+ return err;
+ }
+
+ err = iSSPData->Write(data, iSendFlags, NULL);
+
+ // If a protocol takes only part of the chain they must update it so that we have the new head
+ __ASSERT_DEBUG(err <= 0 || err == (xfrLen - data.Length()), Panic(EBadByteCount));
+
+ if(err <= 0) // protocol error or flow-off
+ {
+ if(err == 0)
+ {
+ iSendData.Assign(data); // keep the MBuf chain for flow-on. In future we could be cleverer and later free this when MBufs are running low
+ iBlockedOperations|=EWriteFlowedOff;
+ }
+ else
+ {
+ data.Free();
+ }
+ return err;
+ }
+ iSendOffset += err;
+ iSendByteCount -= err;
+ } while(iSendByteCount > 0);
+
+ // We successfully completed.
+ if ( iSendUseMBufs )
+ {
+ // Protection against possible non-deletion by SAP
+ data.Free ();
+ // We have to init the RMBufChain, so that caller see that everything send
+ aMsg->InitMBuf(MSG_PRM(2));
+ }
+ return KErrNone;
+ }
+
+TBool ASocket::CheckRunningAndSetReturn()
+/**
+Check a common set of states and set the return value is required.
+*/
+{
+ switch(State())
+ {
+ case ESStateNull:
+ case ESStateAccepting:
+ PanicSocketClient(ENullSocket);
+ //lint -fallthrough
+ case ESStateDead:
+ case ESStateClosing:
+ SetReturn(KErrBadHandle);
+ return EFalse;
+ case ESStateDisconnected:
+ SetReturn(KErrDisconnected);
+ return EFalse;
+ case ESStateError:
+ SetReturn(iError);
+ return EFalse;
+ default:
+ return ETrue;
+ }
+ }
+
+/**
+Complete any outstanding read operation.
+@param aError error code with which to complete the pending operation
+@return ETrue if a pending operation was completed, else EFalse.
+*/
+TBool ASocket::CompleteRead(TInt aError)
+ {
+ if (IsBlockedRead())
+ {
+ if(iAllocAsync)
+ {
+ iAllocAsync->CancelNewData();
+ }
+ iBlockedOperations&=~EBlockedRead;
+ iReadMsg->CompleteMessage(aError);
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+/**
+Complete any outstanding write operation.
+@param aError error code with which to complete the pending operation
+@return ETrue if a pending operation was completed, else EFalse.
+*/
+TBool ASocket::CompleteWrite(TInt aError)
+ {
+ if (IsBlockedWrite())
+ {
+ if(iAllocAsync)
+ {
+ iAllocAsync->CancelCanSend();
+ }
+ iBlockedOperations&=~EBlockedWrite;
+ iWriteMsg->CompleteMessage(aError);
+ iSendData.Free();
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+void ASocket::CompleteConnect(TInt aError)
+ {
+ if (IsBlockedConnect())
+ {
+ iBlockedOperations&=~EBlockedConnect;
+ iBlockedConnectMsg->CompleteMessage(aError);
+ }
+ }
+
+TBool ASocket::CompleteClose(TInt aError)
+ {
+ if (IsBlockedClose())
+ {
+ iBlockedOperations&=~EBlockedClose;
+ iBlockedCloseMsg->CompleteMessage(aError);
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+void ASocket::CompleteIoctl(TInt aError)
+ {
+ if (IsBlockedIoctl())
+ {
+ iBlockedOperations&=~EBlockedIoctl;
+ iBlockedIoctlMsg->CompleteMessage(aError);
+// LOG(ESockLog::Printf(KESockSessDetailTag, _L8("ASocket::CompleteIoctl completing %08x "), iBlockedIoctl.Handle()) );
+ }
+ }
+
+void ASocket::CompleteSetLocalName( TInt aError )
+ {
+ if (IsBlockedSetLocalName())
+ {
+ // SetLocalName has completed.
+ iBlockedOperations &= ~EBlockedSetLocalName;
+ iBlockedSetLocalNameMsg->CompleteMessage(aError);
+ }
+ }
+
+TUint ASocket::SelectConditionsReady()
+/**
+Which select conditions are ready
+*/
+ {
+
+ TUint flags=0;
+ // Exceptional condition
+ if(iError!=KErrNone)
+ {
+ flags|=KSockSelectExcept;
+ }
+
+ // Ready to read - either data or an accept is ready
+ if(iDataAvailable
+ || ((iSelectFlags & KSockReadContinuation) != 0 && !iDatagramTail.IsEmpty())
+ || (State()==ESStateOpeningPassive && iAcceptQ->Count())
+ || (iBlockedOperations&EReadStopped))
+ {
+ flags|=KSockSelectRead;
+ }
+
+ // Ready to write - must be connected and cannot be blocking
+ if((State()==ESStateConnected || State()==ESStateOpen || State()==ESStateShuttingDown)
+ && !(iBlockedOperations&EWriteFlowedOff) )
+ {
+ flags|=KSockSelectWrite;
+ }
+
+ return flags;
+ }
+
+void ASocket::TryToCompleteSelectIoctl()
+/**
+have a go at completing the select ioctl
+*/
+ {
+
+ if(iSelectFlags)
+ {
+ TUint ready = (iSelectFlags & SelectConditionsReady());
+ if(ready)
+ {
+ TPckg<TUint> buf(ready);
+ IoctlComplete(&buf);
+ iSelectFlags=0;
+ }
+ }
+ }
+
+TBool ASocket::CheckReadStopped()
+/**
+Has reading stopped
+*/
+ {
+ if((iBlockedOperations&EReadStopped) && iDataAvailable<=0)
+ {
+ TPtrC8 ptr(0,0);
+ TInt ret = iReadMsg->WriteDes(MSG_PRM(2), ptr);
+ if(iRecvXferLenIdx >= 0)
+ {
+ iXferLength() = 0;
+ ret = iReadMsg->WriteDes(iRecvXferLenIdx, iXferLength);
+ if(ret!= KErrNone)
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+void ASocket::CommunicateOwner()
+/**
+Communicate Thread ID, Process ID and UID to SAP.
+
+*/
+ {
+ if (RequiresOwnerInfo())
+ {
+
+ TSoOwnerInfo info;
+
+ // Not using more Networking specific macro SYMBIAN_NETWORKING_UPS because this support
+ // is required by UPS functionality outside of Networking subsystem as well.
+ GetOwnerInfo(info.iProcessId, info, info.iThreadId);
+
+ iSSP->SetOption(KSOLProvider, KSoOwnerInfo, TPckgC<TSoOwnerInfo>(info));
+
+#ifdef SYMBIAN_NETWORKING_UPS
+ iSSP->SetOption(KSOLProvider, KSoSetPlatSecApi, TPckgC<const MPlatsecApiExt*>(this));
+#endif
+ }
+ }
+
+TInt ASocket::GetConnectionSocketInfo(TConnectionSocketInfo& aInfo) const
+/**
+Return information about this socket
+*/
+ {
+ __ASSERT_DEBUG(iSSP, User::Panic(KSpecAssert_ESockSSocksntsck, 10));
+
+ if(iIsBound)
+ {
+ iSSP->LocalName(aInfo.iSourceAddress);
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+
+ if (State()==ESStateConnected || State()==ESStateOpeningActive || State()==ESStateShuttingDown)
+ {
+ iSSP->RemName(aInfo.iDestinationAddress);
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+
+ __ASSERT_DEBUG(iProtocolInfo, User::Panic(KSpecAssert_ESockSSocksntsck, 11));
+
+ aInfo.iAddressFamily = iProtocolInfo->iAddrFamily;
+ aInfo.iProtocol = iProtocolInfo->iProtocol;
+
+ return KErrNone;
+ }
+
+TInt ASocket::RequestAsyncMBufAllocation(TInt aSignal, TUint aSize)
+ {
+ TInt ret = KErrNone;
+ if(!iAllocAsync)
+ {
+ TRAP(ret, iAllocAsync = CWaitForMBufs::NewL(this));
+ if(ret != KErrNone)
+ {
+ // This second-chance mechanism has failed; it's now reasonable just to error the client
+ Error(KErrNoMemory, aSignal == CWaitForMBufs::ECanSend? MSessionControlNotify::EErrorSend: MSessionControlNotify::EErrorRecv);
+ }
+ }
+
+ if(aSignal == CWaitForMBufs::ENewData)
+ {
+ iAllocAsync->AllocWaitAndSignalNewData(aSize);
+ }
+ else
+ {
+ if(aSignal == CWaitForMBufs::ECanSend)
+ {
+ iAllocAsync->AllocWaitAndSignalCanSend(aSize);
+ }
+ }
+
+ return ret;
+ }
+
+void ASocket::ReadParamL(TSocketMessage aMessage, TInt aSrcParamIndex,TDes8 &aDes,TInt anOffset)
+ {
+ User::LeaveIfError(GetUserMessage(aMessage)->ReadDes(aSrcParamIndex, aDes, anOffset));
+ }
+
+void ASocket::ReadParamL(TSocketMessage aMessage, TInt aSrcParamIndex, RMBufChain& aBufChain)
+ {
+ User::LeaveIfError(GetUserMessage(aMessage)->ReadMBuf(aSrcParamIndex, aBufChain));
+ }
+
+void ASocket::WriteParamL(TSocketMessage aMessage, TInt aDstParamIndex,const TDesC8& aDes,TInt anOffset)
+ {
+ User::LeaveIfError(GetUserMessage(aMessage)->WriteDes(aDstParamIndex, aDes, anOffset));
+ }
+
+void ASocket::WriteParamL(TSocketMessage aMessage, TInt aDstParamIndex, RMBufChain& aBufChain)
+ {
+ User::LeaveIfError(GetUserMessage(aMessage)->WriteMBuf(aDstParamIndex, aBufChain));
+ }
+
+AMessage* ASocket::GetUserMessage( TSocketMessage aMessage ) const
+ {
+ AMessage* msg = NULL;
+ switch (aMessage)
+ {
+ case ESocketCurrentMessage:
+ msg = iCurrentMsg;
+ break;
+
+ case ESocketReadMessage:
+ msg = iReadMsg;
+ break;
+
+ case ESocketWriteMessage:
+ msg = iWriteMsg;
+ break;
+
+ case ESocketCloseMessage:
+ msg = iBlockedCloseMsg;
+ break;
+
+ case ESocketIoCtlMessage:
+ msg = iBlockedIoctlMsg;
+ break;
+
+ case ESocketConnectMessage:
+ msg = iBlockedConnectMsg;
+ break;
+ case ESocketSetLocalNameMessage:
+ msg = iBlockedSetLocalNameMsg;
+ break;
+
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 12));
+ }
+ return msg;
+ }
+
+void ASocket::SetUserMessage ( TSocketMessage aMessageType, AMessage* aMessage )
+ {
+ switch (aMessageType)
+ {
+ case ESocketCurrentMessage:
+ iCurrentMsg = aMessage;
+ break;
+
+ case ESocketReadMessage:
+ iReadMsg = aMessage;
+ break;
+
+ case ESocketWriteMessage:
+ iWriteMsg = aMessage;
+ break;
+
+ case ESocketCloseMessage:
+ iBlockedCloseMsg = aMessage;
+ break;
+
+ case ESocketIoCtlMessage:
+ iBlockedIoctlMsg = aMessage;
+ break;
+
+ case ESocketConnectMessage:
+ iBlockedConnectMsg = aMessage;
+ break;
+ case ESocketSetLocalNameMessage:
+ iBlockedSetLocalNameMsg = aMessage;
+ break;
+
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 13));
+ }
+ }
+
+
+#ifdef SYMBIAN_NETWORKING_UPS
+TInt ASocket::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+/**
+Retrieve the process and thread id associated with the pending request.
+*/
+ {
+ TSocketMessage msg = ESocketCurrentMessage;
+
+ if (IsBlockedConnect())
+ {
+ msg = ESocketConnectMessage;
+ }
+ else
+ if (IsBlockedWrite())
+ {
+ msg = ESocketWriteMessage;
+ }
+ if (msg != ESocketCurrentMessage || (iState == ESStateCreated || iState == ESStateOpen))
+ {
+ // Guard against an invalid current message - especially for a Connect/CancelConnect scenario
+ // whereby the socket is in the ESStateError state. Needs revisiting.
+ return GetUserMessage(msg)->GetProcessAndThreadId(aProcessId, aThreadId);
+ }
+ else
+ {
+ return KErrUnknown;
+ }
+ }
+
+TInt AMessage::GetProcessAndThreadId(TProcessId& /*aProcessId*/, TThreadId& /*aThreadId*/) const
+ {
+ return KErrNotSupported;
+ }
+
+#endif
+