diff -r 000000000000 -r af10295192d8 networkprotocols/tcpipv4v6prt/src/in_trans.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkprotocols/tcpipv4v6prt/src/in_trans.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,935 @@ +// Copyright (c) 2006-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: +// in_trans.cpp - transport layer protocol base +// + +#include "in_trans.h" +#include "inet6log.h" + +#include +#include + +// speed optimisations +#ifdef __ARMCC__ +#pragma push +#pragma arm +#endif + +#define SYMBIAN_NETWORKING_UPS + +CProtocolInet6Transport::CProtocolInet6Transport() + { + // Initialize random seed value + TTime currentTime; + currentTime.HomeTime(); + iSeed = currentTime.Int64() + User::TickCount(); + } + + +void CProtocolInet6Transport::InitL(TDesC& aTag) + { + CProtocolInet6Base::InitL(aTag); + } + + +void CProtocolInet6Transport::StartL() + { + CProtocolInet6Base::StartL(); + } + + +CProtocolInet6Transport::~CProtocolInet6Transport() + { + } + + +TInt CProtocolInet6Transport::Send(RMBufChain& /*aPacket*/,CProtocolBase* /*aSourceProtocol=NULL*/) + { + Panic(EInet6Panic_NotSupported); + return 0; + } + + +// +// Bind request from a protocol above us +// +void CProtocolInet6Transport::BindL(CProtocolBase* /*aProtocol*/, TUint /*aId*/) + { + Panic(EInet6Panic_NotSupported); + } + + +// +// Find SAP based on end-point addresses. +// +// This routine is rather involved, because it is used for a number of different +// purposes. The routine returns a "best match" socket provider based on source +// and destination socket addresses (IP address & port), or NULL if no mathing +// provider is found (see below for an explanation on how matches are ranked). +// +// The method supports the following forms: +// +// o LocateProvider(minimum rank, local socket address); or +// LocateProvider(minimum rank, local socket address, unspecified socket address); +// +// This form is used when binding a socket in order to check that the port is +// not already in use. At least local port must be specified. Local address +// may be unspecified. The first provider that matches the local port (and +// local address, if given) is returned. +// +// o LocateProvider(minimum rank, local socket address, remote socket address); +// +// This form is used in order to locate the correct socket provider, when +// a transport PDU has been received. For this use, the complete local +// and remote addresses must be specified. +// +// Another use of this form is to verify the uniqueness of the source/destination +// socket address pair when creating a new connection. This is only an issue if +// the source port has been explicitly bound and local address reuse has been enabled. +// In this case, the destination socket address MUST be unique among all connections +// terminating in the same local socket address. +// +// Note: for the latter use, local IP address may be left unspecified. In this case, +// it matches all addresses. Local port is mandatory. +// +// The minimum rank parameter specifies the minimum acceptable accuracy of the match. +// The the match with the highest rank found is returned, or NULL if no match of +// at least the requested rank is found. +// +// Matches are ranked as follows (highest rank first): +// +// EMatchExact or EMatchConnection: +// +// Both local and remote socket addresses match. Local IP address may be +// unspecified, if the connection is waiting for a flow to become ready. +// +// This rank is only relevant if caller specified a remote address. +// The returned socket provider handles a connected socket. +// +// EMatchServerSpecAddr: +// +// Local socket address matches and remote socket address is unspecified. +// +// This means that the returned socket provider handles a server socket +// that has been bound to a specific local address. +// +// EMatchServerUnspecAddr: +// +// Local port matches. Local IP address is unspecified. Remote socket address +// is unspecified. +// +// This means that the returned socket provider handles a server socket +// that has been bound to an unspecified address. +// +// EMatchLocalPort: +// +// Local port must match. Local IP address or remote socket address are not tested. +// +// This means that the returned socket provider will conflict with an attempted +// bind() if the KSoReuseAddr socket option is not used. +// +#ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING +CProviderInet6Transport* CProtocolInet6Transport::LocateSap(TProviderMatchEnum aRank, TUint aFamily, +const TInetAddr& aLocalAddr, const TInetAddr& aRemoteAddr, CProviderInet6Base *aSap) +#else +CProviderInet6Transport* CProtocolInet6Transport::LocateSap(TProviderMatchEnum aRank, TUint aFamily, + const TInetAddr& aLocalAddr, const TInetAddr& aRemoteAddr, CProviderInet6Base *aSap, + TUint32 aSourceIfIndex) +#endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + { + ASSERT(aLocalAddr.Port() != KInetPortNone); + + CProviderInet6Transport *sapFound = NULL, *sap; + TUint port = aLocalAddr.Port(); + TProviderMatchEnum rank = (TProviderMatchEnum)(aRank-1); + + // CProtocolInet6Base::LocateProvider() puts us into the right hashed queue. + for (sap = (CProviderInet6Transport *)(aSap != NULL ? aSap : CProtocolInet6Base::LocateProvider(port)); + sap != NULL; sap = (CProviderInet6Transport *)sap->iNextSAP) + { + // If aSap non-NULL, return first match + if (aSap != NULL && rank >= aRank) + break; + + const TInetAddr& local = sap->iFlow.FlowContext()->LocalAddr(); + if (port != local.Port()) + continue; +#ifdef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + // In case of loopback no need to lock interface + if(!aLocalAddr.IsLoopback()) + { + // Port matches this SAP, so if this SAP has an interface that it is + // locked to, confirm the inbound packet is on that interface. That is, + // if the SAP is locked to an interface, this code ensures that the + // packet is only accepted if it is coming over the same interface + // that the SAP is locked to. + TScopeType scoping = sap->iFlow.FlowContext()->LockType(); + TUint32 interfaceNum = sap->iFlow.FlowContext()->LockId(); + + // Check that the source interface index was supplied. Also check for lock id > 0. + // If lock id > 0 this implies that the interface is locked down for this SAP. Also + // ignore the magic value lock id of KNetworkIdFromAddress. + if ((aSourceIfIndex > 0) && (interfaceNum > 0) && (interfaceNum != KNetworkIdFromAddress)) + { + // The sap currently being checked is locked to an interface. Check to + // see what type of lock (scoping) it is. + if (scoping == EScopeType_IF) + { + // This sap is locked to EScopeType_IF + if (interfaceNum != aSourceIfIndex) + { + // Not the right interface, go to next SAP + continue; + } + } + else + { + // Not locked to EScopeType_IF, so now need the network ID and IAP number from the + // interface, to check against one of those. Fetch this from the source interface + // based on the interface index. + const MInterface* iface = sap->iFlow.FlowContext()->Interfacer()->Interface(aSourceIfIndex); + if (iface) + { + if (scoping == EScopeType_IAP) + { + // This sap is locked to EScopeType_IAP. Check if the source interface + // is over the same IAP. + TUint id = iface->Scope(EScopeType_IAP); + if (id != interfaceNum) + { + // IAP does not match that required + continue; + } + } + else if (scoping == EScopeType_NET ) + { + // This sap is locked to EScopeType_NET. Check if the source interface + // is over the same network ID. + TUint id = iface->Scope(EScopeType_NET); + if (id != interfaceNum) + { + // Network ID does not match that required + continue; + } + } + } + } + } + } +#endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + + const CFlowContext *const flow = sap->iFlow.FlowContext(); + + TBool localMatch = aLocalAddr.CmpAddr(local) && + (aLocalAddr.Scope() == 0 || aLocalAddr.Scope() == local.Scope()); + if (!sap->iSockFlags.iAddressSet || localMatch) + { + if (sap->iSockFlags.iConnected) + { + if (localMatch && aRemoteAddr.CmpAddr(flow->RemoteAddr()) + && (aRemoteAddr.Scope() == 0 || aRemoteAddr.Scope() == flow->RemoteAddr().Scope())) + { + rank = EMatchExact; + sapFound = sap; + break; + } + } + else + { + if (rank >= EMatchServerSpecAddr) + continue; + + if (localMatch) + { + rank = EMatchServerSpecAddr; + sapFound = sap; + continue; + } + + if (rank >= EMatchServerUnspecAddr) + continue; + + if (sap->iSockFamily == aFamily || sap->iSockFamily == KAFUnspec || aFamily == KAFUnspec) + { + rank = EMatchServerUnspecAddr; + sapFound = sap; + continue; + } + } + } + + if (rank >= EMatchLocalPort) + continue; + + rank = EMatchLocalPort; + sapFound = sap; + } + +#ifdef _LOG + TBuf<50> src, dst; + //TBuf<50> src2, dst2; + aLocalAddr.OutputWithScope(src); + aRemoteAddr.OutputWithScope(dst); + Log::Printf(_L("\t%S LocateProvider({%S,%d} <--> {%S,%d})"), + &ProtocolName(), &src, port, &dst, aRemoteAddr.Port()); + if (sapFound) + { + TBuf<50> src2, dst2; + sapFound->iFlow.FlowContext()->LocalAddr().OutputWithScope(src2); + sapFound->iFlow.FlowContext()->RemoteAddr().OutputWithScope(dst2); + Log::Printf(_L("\t%S SAP[%u] found {%S,%d} <--> {%S,%d}, rank=%d, family=%x"), + &ProtocolName(), (TInt)sapFound, + &src2, port, &dst2, sapFound->iFlow.FlowContext()->RemotePort(), + rank, aFamily); + } + else + { + Log::Printf(_L("\t%S SAP not found, best rank=%d, family=%x"), &ProtocolName(), rank, aFamily); + } +#endif + + return (CProviderInet6Transport *)sapFound; + } + +#ifdef _LOG +#include "tcp.h" +void CProtocolInet6Transport::LogProviders(TUint aPort) + { + CProviderInet6Base *sap; + TBool title = EFalse; + + for (sap = CProtocolInet6Base::LocateProvider(aPort); sap != NULL; sap = sap->iNextSAP) + { + if (aPort != sap->iFlow.FlowContext()->LocalPort()) + continue; + + if (!title) + { + title = ETrue; + Log::Printf(_L("Active TCBs on %S port %d:"), &ProtocolName(), aPort); + } + + TBuf<50> src, dst; + sap->iFlow.FlowContext()->LocalAddr().OutputWithScope(src); + sap->iFlow.FlowContext()->RemoteAddr().OutputWithScope(dst); + Log::Printf(_L("\t%S SAP[%u] {%S,%d} <--> {%S,%d} [reuse=%d] %s"), + &ProtocolName(), (TInt)sap, + &src, sap->iFlow.FlowContext()->LocalPort(), + &dst, sap->iFlow.FlowContext()->RemotePort(), + ((CProviderInet6Transport*)sap)->iSockFlags.iReuse, + (sap->iFlow.FlowContext()->Protocol() == KProtocolInetTcp) ? + ((CProviderTCP6*)sap)->TcpState() : _S("UDP")); + } + } +#endif + + +// +// Pick a free port by random from the range [32768,61000]. +// Random ephemeral port selection will help counter certain +// types of attacks. +// +TUint CProtocolInet6Transport::AssignAutoPort() + { + TUint i, port = KInetMinAutoPort + Random(KInetMaxAutoPort - KInetMinAutoPort + 1); + + for (i = KInetMinAutoPort; i <= KInetMaxAutoPort; i++) + { + if (CProtocolInet6Base::LocateProvider(port) == NULL) + return port; + if (++port > KInetMaxAutoPort) + port = KInetMinAutoPort; + } + return KInetPortNone; + } + + +TInt CProtocolInet6Transport::GetIniValue( const TDesC &aSection, + const TDesC &aName, + TInt aDefault, + TInt aMin, + TInt aMax, + TBool aBoundMode) const +/** +Reads integer value for ini parameters from tcpip.ini file. + +@param aSection Section under which ini parameter belongs ([xxx] tag). +@param aName Name of the ini parameter. +@param aDefault Default value for the parameter, if not given in ini file. +@param aMin Minimum limit for the parameter value. +@param aMax Maximum limit for the parameter value. +@param aBoundMode If ETrue, values that exceed min or max are truncated back to the min/max + boundary. If EFalse, exceeding values are considered invalid, and default + is used for those parameters. + +@return Integer value for the parameter. +*/ + { + LOG(_LIT(KFormat, "\t[%S] %S = %d")); + LOG(_LIT(KFormatInv, "\t[%S] %S = %d is invalid")); + + TInt value; + if (!Interfacer()->FindVar(aSection, aName, value)) + { + value = aDefault; + } + else + { + if (value < aMin) + { + LOG(Log::Printf(KFormatInv, &aSection, &aName, value)); + value = aBoundMode ? aMin : aDefault; + } + else if (value > aMax) + { + LOG(Log::Printf(KFormatInv, &aSection, &aName, value)); + value = aBoundMode ? aMax : aDefault; + } + } + LOG(Log::Printf(KFormat, &aSection, &aName, value)); + return value; + } + + +// +// Transport Layer Socket Providers +// + +CProviderInet6Transport::CProviderInet6Transport(CProtocolInet6Base *aProtocol) + : CProviderInet6Base(aProtocol) + { + iSockFlags.iRecvClose = EFalse; + iSockFlags.iSendClose = EFalse; + iSockFlags.iConnected = EFalse; + iSockFlags.iFlowStopped = EFalse; + iSockFlags.iNotify = ETrue; + iSockFlags.iReuse = EFalse; + iSockFlags.iAttached = ETrue; +// iSockFlags.iRawMode = EFalse; +// iSockFlags.iHeaderIncluded = EFalse; + iSockFamily = KAFUnspec; + iAppFamily = KAFUnspec; + } + +CProviderInet6Transport::~CProviderInet6Transport() + { + } + + +void CProviderInet6Transport::LocalName(TSockAddr &aAddr) const + { + aAddr = iFlow.FlowContext()->LocalAddr(); + if (iAppFamily == KAfInet) + TInetAddr::Cast(aAddr).ConvertToV4(); + } + + +TInt CProviderInet6Transport::SetLocalName(TSockAddr &aAddr) + { +#ifdef _LOG + TBuf<50> a; TInetAddr::Cast(aAddr).OutputWithScope(a); + LOG(Log::Printf(_L("\t%S SAP[%u] SetLocalName({%S,%d}) [reuse=%d]"), + &ProtocolName(), (TInt)this, + &a, aAddr.Port(), iSockFlags.iReuse)); +#endif + + LOG(((CProtocolInet6Transport*)iProtocol)->LogProviders(aAddr.Port())); + + TInetAddr addr = aAddr; + + // Bound already? + if (iFlow.FlowContext()->LocalPort() != KInetPortNone) + return KErrAlreadyExists; + + // Convert an IPv4 address to a V4 Mapped IPv6 address + if (addr.Family() == KAfInet) + addr.ConvertToV4Mapped(); + + // Check source address + if (addr.Family() != KAFUnspec) + { + iSockFamily = addr.IsV4Mapped() ? KAfInet : KAfInet6; + if (!addr.IsUnspecified()) + { + if (addr.Scope() == 0) + { + // Check address and pick a default scope id + addr.SetScope(iProtocol->Interfacer()->LocalScope(addr.Ip6Address(), + iFlow.FlowContext()->LockId(), iFlow.FlowContext()->LockType())); + if (addr.Scope() == 0) + return KErrNotFound; + } + else + { + // Check scoped address + if (addr.Scope() != iProtocol->Interfacer()->LocalScope(addr.Ip6Address(), + addr.Scope(), (TScopeType)(addr.Ip6Address().Scope() - 1))) + return KErrNotFound; + } + } + } + + // Autobind requested? + if (addr.Port() == KInetPortNone) + { + addr.SetPort(((CProtocolInet6Transport*)iProtocol)->AssignAutoPort()); + if (addr.Port() == KInetPortNone) + return KErrInUse; + } + else + { + if (addr.Port() > 65535) + return KErrTooBig; + + if (!iSockFlags.iReuse && Protocol()->LocateSap(EMatchLocalPort, aAddr.Family(), addr)) + return KErrInUse; + } + + iAppFamily = aAddr.Family(); // aAddr here to get the original family + CProviderInet6Base::SetLocalName(addr); + iSockFlags.iAddressSet = iFlow.FlowContext()->IsLocalSet(); + iProtocol->BindProvider(this); + return KErrNone; + } + +void CProviderInet6Transport::RemName(TSockAddr &aAddr) const + { + aAddr = iFlow.FlowContext()->RemoteAddr(); + if (iAppFamily == KAfInet) + TInetAddr::Cast(aAddr).ConvertToV4(); + } + + +TInt CProviderInet6Transport::SetRemName(TSockAddr &aAddr) + { + //__ASSERT_DEBUG(!iSockFlags.iConnected && iFlow.FlowContext()->RemoteAddr().IsUnspecified() && iFlow.FlowContext()->RemotePort() == KInetPortNone, + // Panic(EInet6Panic_NotSupported)); + TInetAddr addr = aAddr; + +#ifdef _LOG + TBuf<50> a; addr.OutputWithScope(a); + LOG(Log::Printf(_L("\t%S SAP[%u] SetRemName({%S,%d})"), &ProtocolName(), (TInt)this, &a, addr.Port());) +#endif + TUint port = addr.Port(); + if (port < 1) + return KErrGeneral; + else if (port > 65535) + return KErrTooBig; + + if (addr.IsUnspecified()) + return KErrBadName; + + if (addr.Family() == KAfInet) + addr.ConvertToV4Mapped(); + + TInt family = addr.IsV4Mapped() ? KAfInet : KAfInet6; + + if(iSockFamily == KAFUnspec) + iSockFamily = family; + else if (iSockFamily != family) + return KErrBadName; + + iFlow.SetRemoteAddr(addr); + iAppFamily = aAddr.Family(); + + iSockFlags.iConnected = ETrue; + return KErrNone; + } + + +void CProviderInet6Transport::AutoBind() + { + //__ASSERT_DEBUG(iFlow.FlowContext()->LocalPort()==KInetPortNone, Panic(EInet6Panic_BadBind)); + TInetAddr localAddr; + + // Socket is already bound? + if (iFlow.FlowContext()->LocalPort()!=KInetPortNone) + return; + + localAddr.SetPort(((CProtocolInet6Transport *)iProtocol)->AssignAutoPort()); + if (localAddr.Port()==KInetPortNone) + { + Error(KErrInUse); + return; + } + + iFlow.SetLocalAddr(localAddr); + +#ifdef _LOG + TBuf<50> addr; iFlow.FlowContext()->LocalAddr().OutputWithScope(addr); + Log::Printf(_L("\t%S SAP[%u] AutoBind() --> {%S,%d}"), &ProtocolName(), (TInt)this, &addr, iFlow.FlowContext()->LocalPort()); +#endif + + iProtocol->BindProvider(this); + } + +TInt CProviderInet6Transport::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption) + { + TInt ret = KErrNotSupported; + + if (aLevel == KSolInetIp && aName == KSoReuseAddr) + { + TInt intValue; + ret = GetOptionInt(aOption, intValue); + if (ret == KErrNone) + iSockFlags.iReuse = intValue ? TRUE : FALSE; + #ifdef _LOG + Log::Printf(_L("SetOpt\t%S SAP[%u] KSoReuseAddr = %d err=%d"), + &ProtocolName(), (TInt)this, (TInt)iSockFlags.iReuse, ret); + #endif + } + + if (ret == KErrNotSupported) + ret = CProviderInet6Base::SetOption(aLevel, aName, aOption); + +#ifdef SYMBIAN_NETWORKING_UPS + if (ret == KErrNone && aLevel == KSOLProvider && aName == (TUint) KSoConnectionInfo) + { + iConnectionInfoReceived = 1; + } +#endif + + return ret; + } + + +TInt CProviderInet6Transport::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const + { + TInt ret = KErrNotSupported; + + if (aLevel == KSolInetIp && aName == KSoReuseAddr) + ret = SetOptionInt(aOption, iSockFlags.iReuse); + + if (ret == KErrNotSupported) + ret = CProviderInet6Base::GetOption(aLevel, aName, aOption); + + return ret; + } + +void CProviderInet6Transport::CanSend() + { + LOG(Log::Printf(_L("\t%S SAP[%u] CanSend()"), &ProtocolName(), (TInt)this)); + // Do not enable data flow if the protocol doesn't want it. + if(!iSockFlags.iFlowStopped && iSockFlags.iNotify) + CProviderInet6Base::CanSend(); + } + +void CProviderInet6Transport::Error(TInt aError, TUint aOperationMask) + { + if (iSockFlags.iNotify) + CProviderInet6Base::Error(aError, aOperationMask); + if (FatalState()) + iSockFlags.iNotify = EFalse; + } + +void CProviderInet6Transport::IcmpError(TInt aError, TUint aOperationMask, TInt aType, TInt aCode, + const TInetAddr& aSrcAddr, const TInetAddr& aDstAddr, const TInetAddr& aErrAddr) + { + CProviderInet6Base::SaveIcmpError(aType, aCode, aSrcAddr, aDstAddr, aErrAddr); + if (iAppFamily == KAfInet) + { + iLastError.iSrcAddr.ConvertToV4(); + iLastError.iDstAddr.ConvertToV4(); + iLastError.iErrAddr.ConvertToV4(); + } + + if (iSockFlags.iReportIcmp && aError != KErrNone) + Error(aError, aOperationMask); + } + +#ifdef SYMBIAN_NETWORKING_UPS +TBool CProviderInet6Transport::ConnectionInfoSet() + { + return static_cast(iConnectionInfoReceived); + } + + +TBool CProviderInet6Transport::HasSocket() + { + if (iSocket == NULL) + { + return EFalse; + } + else + { + return ETrue; + } + } + +void *CProviderInet6Transport::GetApiL(const TDesC8& aApiName, TUint* aVersion) + { + if (aApiName == _L8("MProviderBindings")) + { + return EXPORT_API_L(MProviderBindings, static_cast(this), aVersion); + } + + return NULL; + } +#endif + +void RMBufSockQ::AppendL(const TDesC8& aData, TInt aLen) + { + if (aLen <= 0) + return; + + RMBufChain seg; + seg.AllocL(aLen); + seg.CopyIn(aData); + RMBufChain::Append(seg); + } + +TInt RMBufSockQ::AppendDes(const TDesC8& aData, TInt aLen) + { + if (aLen <= 0) + return KErrNone; + + RMBufChain seg; + TInt err = seg.Alloc(aLen); + if(err == KErrNone) + { + seg.CopyIn(aData); + RMBufChain::Append(seg); + } + return err; + } + + +// +// Append at least aLength bytes from aChain. +// Leave the remainder in aChain. Return number +// of bytes removed from aChain. +// +TInt RMBufSockQ::AppendAtLeast(RMBufChain& aChain, TInt aLength) + { + TInt o, n; + RMBuf* m, *p; + + if (!aChain.Goto(aLength, m, o, n, p)) + { + aLength = aChain.Length(); + RMBufChain::Append(aChain); + return aLength; + } + + if (o != m->Offset()) + { + p = m; + m = m->Next(); + aLength += n; + } + + p->Unlink(); + RMBufChain::Append(aChain); + aChain = m; + + return aLength; + } + +// +// Remove at most aLength bytes from the queue. +// Place the result in aChain. Return number +// of bytes removed from the queue. +// +TInt RMBufSockQ::RemoveAtMost(RMBufChain& aChain, TInt aLength) + { + TInt o, n; + RMBuf* m, *p; + + if (aLength <= 0 || iNext == NULL) + return 0; + + if (!Goto(aLength, m, o, n, p)) + { + aChain = iNext; + iNext = NULL; + return aChain.Length(); + } + + p->Unlink(); + aChain = iNext; + iNext = m; + + return aLength + m->Offset() - o; + } + +// +// Copy aLength bytes from aQueue at aOffset +// +void TDualBufPtr::CopyInL(const RMBufChain& aQueue, TInt aOffset, TInt aLength) + { + switch(iType) + { + case ERMBufChain: + if (aLength > 0) + aQueue.CopyL(*iChain, aOffset, aLength); + break; + + case EDes8: + iDesc->SetLength(aLength); + if (aLength > 0) + aQueue.CopyOut(*iDesc, aOffset); + break; + + default: + Panic(EInet6Panic_NotSupported); + } + } + +// +// Copy aLength bytes from aQueue at aOffset +// +TInt TDualBufPtr::CopyIn(const RMBufChain& aQueue, TInt aOffset, TInt aLength) + { + switch(iType) + { + case ERMBufChain: + if (aLength > 0) + return aQueue.Copy(*iChain, aOffset, aLength); + break; + + case EDes8: + iDesc->SetLength(aLength); + if (aLength > 0) + aQueue.CopyOut(*iDesc, aOffset); + break; + + default: + Panic(EInet6Panic_NotSupported); + } + return KErrNone; + } + +// +// Copy into aChain at aOffset +// +void TDualBufPtr::CopyOut(RMBufChain& aChain, TInt aOffset) const + { + switch(iType) + { + case EDes8: + case EDesC8: + aChain.CopyIn(*iDesc, aOffset); + break; + + default: + Panic(EInet6Panic_NotSupported); + } + } + +// +// Remove aLength bytes from the beginning of aQueue. +// +TInt TDualBufPtr::Consume(RMBufChain& aQueue, TInt aLength, RMBufAllocator& aAllocator) + { + RMBufChain tail; + TInt err; + + switch(iType) + { + case ERMBufChain: + if (aLength > 0) + { + err = aQueue.Split(aLength, tail, aAllocator); + if (err == KErrNone) + { + iChain->Assign(aQueue); + aQueue.Assign(tail); + } + else + { + aLength = RMBufSockQ::Cast(aQueue).RemoveAtMost(*iChain, aLength); + LOG(Log::Printf(_L("TDualBufPtr::Consume(): Alloc problem. Returning less"))); + } + } + break; + + case EDes8: + iDesc->SetLength(aLength); + if (aLength > 0) + { + aQueue.CopyOut(*iDesc); + aQueue.TrimStart(aLength); + } + break; + + default: + Panic(EInet6Panic_NoData); + } + return aLength; + } + +// +// Append at least aLength bytes to aQueue +// +TInt TDualBufPtr::AppendL(RMBufChain& aQueue, TInt aLength) + { + switch(iType) + { + case ERMBufChain: + aLength = RMBufSockQ::Cast(aQueue).AppendAtLeast(*iChain, aLength); + break; + + case EDes8: + case EDesC8: + RMBufSockQ::Cast(aQueue).AppendL(*iDesc, aLength); + break; + + default: + Panic(EInet6Panic_NoData); + } + + return aLength; + } + +// +// Append at least aLength bytes to aQueue. Panics if used with des-tyoe +// +TInt TDualBufPtr::Append(RMBufChain& aQueue, TInt aLength) + { + switch(iType) + { + case ERMBufChain: + aLength = RMBufSockQ::Cast(aQueue).AppendAtLeast(*iChain, aLength); + break; + + default: + Panic(EInet6Panic_NoData); + } + + return aLength; + } + +// +// Free buffer +// +void TDualBufPtr::Free() + { + switch(iType) + { + case ERMBufChain: + iChain->Free(); + break; + + case EDes8: + iDesc->SetLength(0); + break; + + default: + Panic(EInet6Panic_NoData); + } + } + +#ifdef __ARMCC__ +#pragma pop +#endif