Start breaking the dependency of backend.dll on bluetooth.dll - commit copies of the original ossrv files from PDK 3.0.2
/*
* Copyright (c) 1997-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:
*
*/
#include <sys/types.h>
#include <string.h> // for memcpy
#include <fcntl.h> // for struct stat
#include <sys/errno.h> // for ENOTSOCK
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <netinet/in.h> // for htons
#include <sys/sockio.h>
#include <bt_sock.h> // Symbian BT constantss needed for cooperation with Symbian sockets
#include <arpa/inet.h>
#include <es_sock.h>
#include <in_sock.h>
#include <net/if.h>
#include <commdb.h>
#include <cdbcols.h>
#include <commdbconnpref.h>
#include <e32base.h>
#include <e32err.h>
#include <utf.h>
#include <e32std.h>
#include <net/route.h>
#include <in_iface.h>
#include "fdesc.h"
#include "lposix.h"
#include "sysif.h"
// Support for struct sockaddr conversion
TUSockAddr::TUSockAddr (TAny* aBuf)
: TSockAddr(), iError(0)
{
Prepare(aBuf);
}
void TUSockAddr::Prepare (TAny* aBuf)
//
// Prepare a TUSockAddr to receive an address (used in RecvFrom)
// Setting the length to 0 indicates that we don't really want this address anyway.
//
{
if (aBuf==0)
{
SetLength(0);
iError = EFAULT;
return;
}
}
EXPORT_C TUSockAddr::TUSockAddr (const TAny* aBuf, TUint aLen)
: TSockAddr(), iError(0)
{
Set(aBuf,aLen);
}
void TUSockAddr::Set (const TAny* aBuf, TUint aLen)
//
// Construct an ESOCK TSockAddr from a struct sockaddr.
// We have to deal with the network byte ordering of AF_INET addresses
//
{
if (!aBuf)
{
iError = EFAULT;
SetLength(0);
return;
}
const TUint dataOffset = (TUint)&((struct sockaddr *)0)->sa_data[0];
// aLen should be atleast have minimum size.
if (aLen < dataOffset)
{
iError = EINVAL;
SetLength(0);
return;
}
const struct sockaddr* sp= (const struct sockaddr *)(aBuf);
TUint8 *from=(TUint8*)aBuf;
if (sp->sa_family==AF_INET)
{
// byte-swap sockaddr_in back into host ordering
TUint port=(from[2]<<8)+from[3];
from+=4;
TUint32 addr=(from[0]<<24)+(from[1]<<16)+(from[2]<<8)+from[3];
from+=4;
SetFamily(AF_INET);
SetPort(port);
*(TUint32*)UserPtr()=addr;
SetUserLen(4);
return;
}
else if (sp->sa_family == AF_INET6)
{
SetFamily(sp->sa_family);
SetPort(ByteOrder::Swap16(sp->sa_port));
from+=4;
// copy the rest of the data as given
TUint8 *to=UserPtr();
if (aLen<4)
aLen=4;
aLen-=4; // skip fmaily and port
if (aLen>24)
aLen=24;
memcpy(to,from,aLen);
SetUserLen(aLen);
return;
}
else if (sp->sa_family == KBTAddrFamily)
{
// Make a TBTSockAddr from a sockaddr_bt...
TBTSockAddr tmpAddr;
// Family is always Bluetooth:
tmpAddr.SetFamily(KBTAddrFamily);
// The port number has the correct byte order already, as the
// POSIX Bluetooth APIs assume litle-endian format:
tmpAddr.SetPort(sp->sa_port);
// For the address we need to reverse the byte ordering, as
// Symbian appears to index Bluetooth addresses in a
// big-endian manner:
const TInt KBTAddrLength = 6; // Bytes in a Bluetooth address
const TInt KBTAddrOffset = 4; // Offset of address in sockaddr_bt
TBTDevAddr devAddr;
const TInt KMinLength = KBTAddrLength + KBTAddrOffset;
if (aLen >= KMinLength)
{
for (TInt i=0; i<KBTAddrLength; ++i)
{
devAddr[i] = from[KMinLength - 1 - i];
}
}
tmpAddr.SetBTAddr(devAddr);
// Security settings:
TBTServiceSecurity sec;
sec.SetUid(TUid::Uid(0));
sec.SetAuthentication(EFalse);
sec.SetEncryption(EFalse);
sec.SetAuthorisation(EFalse);
sec.SetDenied(EFalse);
tmpAddr.SetSecurity(sec);
// Now we must copy the contents of the "tmpAddr" TBTSockAddr,
// but unfortunately there isn't an assignment operator for us
// to use. Still, we know it is a self-contained T class for
// which a direct shallow copy using memcopy() will be ok:
//
memcpy(this, &tmpAddr, sizeof(TBTSockAddr));
return;
}
else
{
// Not AF_INET or KBTAddrFamily:
// expand the family and port
SetFamily(sp->sa_family);
SetPort(sp->sa_port);
from+=4;
// copy the rest of the data as given
TUint8 *to=UserPtr();
if (aLen<4)
aLen=4;
aLen-=4; // skip fmaily and port
if (aLen>24)
aLen=24;
memcpy(to,from,aLen);
SetUserLen(aLen);
}
}
/*
* Extract a struct sockaddr from a TSockAddr
*/
EXPORT_C void TUSockAddr::Get(TAny* addr, unsigned long* len)
{
if (addr==0)
{
iError = EFAULT;
SetLength(0);
return;
}
const TUint dataOffset = (TUint)&((struct sockaddr *)0)->sa_data[0];
// aLen should be atleast have minimum size.
if (*len < dataOffset)
{
iError = EINVAL;
SetLength(0);
return;
};
struct sockaddr* sp=(struct sockaddr*)addr;
TUint16 port=(TUint16)Port();
//The ipv4 address could be obtained either as
//plain 32 bit address or as ipv4 mapped ipv6 address
TInetAddr inetAddr(*this);
TBool isV4Mapped = (Family()==AF_INET6) && (inetAddr.IsV4Mapped() || inetAddr.IsV4Compat());
if (Family()==AF_INET || isV4Mapped)
{
sp->sa_family=AF_INET;
sp->sa_port= ByteOrder::Swap16(port);
TUint8* from=UserPtr();
TUint32 fromaddr;
//If the address is v4 mapped, we take the last 4 bytes from the 16 bytes long v6 structure.
if(isV4Mapped)
fromaddr = (from[15]<<24)+(from[14]<<16)+(from[13]<<8)+from[12];
else
fromaddr = (from[0]<<24)+(from[1]<<16)+(from[2]<<8)+ from[3];
*(TUint32*)sp->sa_data=fromaddr;
*len=8;
return;
}
else if (Family()==AF_INET6)
{
sp->sa_family=(TUint16)Family();
sp->sa_port=ByteOrder::Swap16(port);
TUint ulen=GetUserLen();
if (ulen+4>(*len))
ulen=(*len)-4;
*len=ulen+4;
memcpy(sp->sa_data,UserPtr(),ulen);
sp->sa_len = ulen;
return;
}
else if (Family()==KBTAddrFamily)
{
sp->sa_family=KBTAddrFamily;
sp->sa_port=port;
const TInt KBTAddrLength = 6;
if (GetUserLen() == KBTAddrLength)
{
for (TInt i=0; i<KBTAddrLength; ++i)
{
sp->sa_data[KBTAddrLength - 1 - i] = UserPtr()[i];
}
}
return;
}
else
{
// Not AF_INET or KBTAddrFamily:
sp->sa_family=(TUint16)Family();
sp->sa_port=port;
TUint ulen=GetUserLen();
if (ulen+4>(*len))
ulen=(*len)-4;
*len=ulen+4;
memcpy(sp->sa_data,UserPtr(),ulen);
}
}
// The Socket descriptor class
CSocketDesc::CSocketDesc()
:iIoctlBuf(0,0),
iSocketPtr(NULL),
iConnPref(),
iConnectionPtr(NULL),
iSubConnectionPtr(NULL),
iRConnectionIndex(-1),
iSockServPtr(NULL)
{
};
TInt CSocketDesc::Socket(RSocketServ& aSs, int family, int style, int protocol)
{
if (protocol == 0)
{
if (family == AF_INET)
{
switch (style)
{
case SOCK_STREAM:
protocol = IPPROTO_TCP;
break;
case SOCK_DGRAM:
protocol = IPPROTO_UDP;
break;
}
}
else
{
protocol = KUndefinedProtocol;
}
}
iFcntlFlag = 0;
TInt err = CreateLock();
if (err)
{
return err;
}
if (family == AF_INET6)
{
err = iSocket.Open(aSs, KAfInet, style, protocol);
}
else
{
err = iSocket.Open(aSs, family, style, protocol);
}
if (err == KErrNone)
{
iStyle = style;
iSocket.Close(); // We will close now, to open later using connection preferences
iAddrFamily = family;
iProtocol = protocol;
iSockServPtr = &aSs; // Saving the const session pointer for later use
}
return err;
}
TInt CSocketDesc::FinalClose()
{
CLocalSystemInterface* backend = Backend();
backend->DefConnLock().Wait();
RHeap* oheap = User::SwitchHeap(backend->Heap());
if (iSocketPtr != NULL)
{
iSocketPtr = NULL;
StopInterface(NULL); // Checks for RConnection as well as RSubConnection
backend->RemoveSocket(this);
}
CSockDescBase::FinalClose();
User::SwitchHeap(oheap);
backend->DefConnLock().Signal();
return KErrNone;
}
void CSocketDesc::Read (TDes8& aBuf, TRequestStatus& aStatus)
{
//Acquire the Lock before read and release it later
iReadLock.Wait();
if (iSocketPtr == NULL)
{
TInt ret = OpenUsingPreference();
if (ret != KErrNone) // Error in open
{
Complete(aStatus,ret);
iReadLock.Signal();
return;
}
}
CSockDescBase::Read (aBuf,aStatus);
iReadLock.Signal();
}
TInt CSocketDesc::ReadCompletion(TDes8& aBuf, TInt aStatus)
{
return CSockDescBase::ReadCompletion(aBuf, aStatus);
}
void CSocketDesc::ReadCancel()
{
if (iSocketPtr != NULL)
{
CSockDescBase::ReadCancel();
}
}
void CSocketDesc::Write (TDes8& aBuf, TRequestStatus& aStatus)
{
TInt err = maybe_reopen_socket();
if (err != KErrNone)
{
Complete(aStatus, err);
return;
}
iWriteLock.Wait();
CSockDescBase::Write(aBuf, aStatus);
iWriteLock.Signal();
}
void CSocketDesc::WriteCancel()
{
if (iSocketPtr != NULL)
{
CSockDescBase::WriteCancel();
}
}
TInt CSocketDesc::Bind(const struct sockaddr* aAddr, unsigned long aSize)
{
TInt ret;
TUSockAddr addr(aAddr,aSize);
if (addr.iError != 0)
{
return addr.iError;
}
ret = maybe_reopen_socket();
if (ret != KErrNone)
return ret;
ATOMICSOCKETOP(ret = iSocket.Bind(addr),return KErrBadHandle)
return ret;
}
TInt CSocketDesc::Listen(TUint qSize)
{
TInt ret;
if (iStyle == SOCK_DGRAM) // Listen on UDP socket, crashing at RSocket::Listen().
{
return EOPNOTSUPP;
}
ret = maybe_reopen_socket();
if (ret != KErrNone)
return ret;
return CSockDescBase::Listen(qSize);
}
TInt CSocketDesc::SockName(int anEnd, struct sockaddr* anAddr,unsigned long* aSize)
{
if (!anAddr)
{
return EFAULT;
}
TInt ret = maybe_reopen_socket();
if (ret != KErrNone)
return ret;
struct sockaddr temp;
unsigned long len = sizeof( temp );
TUSockAddr nSockAddr(&temp, len );
ret = CSockDescBase::SockName(anEnd,nSockAddr);
if(ret == KErrNone )
{
nSockAddr.Get(&temp,&len );
if( *aSize > len )
*aSize = len;
memcpy( anAddr,&temp,*aSize);
}
return ret;
}
TInt CSocketDesc::GetSockOpt(TInt anOptionName, TInt anOptionLevel, TDes8& anOption)
{
TInt ret;
if (anOption.Ptr() == NULL)
{
return EFAULT;
}
if (anOption.Length() == 0)
{
return EINVAL;
}
ret = maybe_reopen_socket();
if (ret != KErrNone)
return ret;
if (SO_TYPE == anOptionName && SOL_SOCKET == anOptionLevel)
{
TProtocolDesc protocolInfo;
ATOMICSOCKETOP(ret = iSocket.Info(protocolInfo), ret = KErrBadHandle)
if (KErrNone == ret )
{
// Copy the Socket Type to the buffer
TInt size = (anOption.Length() < sizeof(protocolInfo.iSockType))? anOption.Length(): sizeof(protocolInfo.iSockType);
Mem::Copy((unsigned char*)anOption.Ptr(), &protocolInfo.iSockType, size);
anOption.SetLength(size);
}
return ret;
}
if(IPPROTO_IP == anOptionLevel && IP_MULTICAST_IF == anOptionName)
{
TUSockAddr addr;
struct sockaddr_in sockAddress;
sockAddress.sin_family = AF_INET;
ATOMICSOCKETOP(sockAddress.sin_port = iSocket.LocalPort(),return KErrBadHandle)
ATOMICSOCKETOP(iSocket.LocalName(addr);,return KErrBadHandle)
TInt a = sizeof(sockAddress);
addr.Get(&sockAddress,(unsigned long*)&a);
TInt size = (anOption.Length() < sizeof(sockAddress.sin_addr))? anOption.Length(): sizeof(sockAddress.sin_addr);
Mem::Copy((unsigned char*)anOption.Ptr(), &(sockAddress.sin_addr), size);
anOption.SetLength(size);
return KErrNone;
}
switch(anOptionLevel)
{
case IPPROTO_TCP:
anOptionLevel=SOL_TCP;
break;
case IPPROTO_IP:
anOptionLevel=SOL_IP;
break;
case SOL_SOCKET:
{
switch(anOptionName)
{
case SO_REUSEADDR:
anOptionLevel=SOL_IP;
break;
case SO_OOBINLINE:
case SO_KEEPALIVE:
anOptionLevel=SOL_TCP;
break;
case SO_BROADCAST:
*((TInt*)anOption.Ptr()) = 1;
return KErrNone;
}
}
}
switch(anOptionName)
{
case IP_MULTICAST_TTL:
anOptionLevel=KSolInetIp;
anOptionName=KSoIp6MulticastHops;
break;
case IP_MULTICAST_LOOP:
anOptionLevel=KSolInetIp;
anOptionName=KSoIp6MulticastLoop;
break;
}
ATOMICSOCKETOP(ret = iSocket.GetOpt(anOptionName,anOptionLevel,anOption), return KErrBadHandle)
return ret;
}
TInt CSocketDesc::GetInterfaceIndex(TUint32 anAddr)
{
TPckgBuf<TSoInetIfQuery> ifq;
TInt aIndex = -1;
if (KInetAddrAny == anAddr)
{
aIndex = 0;
return aIndex;
}
else
{
TInt ret = KErrNone;
ATOMICSOCKETOP(ret = iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl), ret = KErrBadHandle)
if (ret != KErrNone)
return KErrGeneral;
TPckgBuf<TSoInetInterfaceInfo>iface;
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, iface), ret = KErrBadHandle )
while(ret == KErrNone)
{
TSoInetInterfaceInfo &info = iface();
TInt result;
if(info.iState == EIfUp)
{
if (anAddr == info.iAddress.Address())
{
ifq().iName = info.iName;
ATOMICSOCKETOP( result = iSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, ifq), result = KErrBadHandle )
if (result == KErrNone)
aIndex = ifq().iIndex;
}
}
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, iface), ret = KErrBadHandle )
}
}
return aIndex;
}
TInt CSocketDesc::SetSockOpt(TInt anOptionName, TInt anOptionLevel, TDesC8& anOption)
{
TInt ret;
if (anOption.Ptr() == NULL)
{
return EFAULT;
}
if (anOption.Length() == 0)
{
return EINVAL;
}
ret = maybe_reopen_socket();
if (ret != KErrNone)
return ret;
switch(anOptionLevel)
{
case IPPROTO_TCP:
anOptionLevel=SOL_TCP;
break;
case IPPROTO_IP:
anOptionLevel=SOL_IP;
break;
case SOL_SOCKET:
{
switch(anOptionName)
{
case SO_REUSEADDR:
anOptionLevel=SOL_IP;
break;
case SO_OOBINLINE:
case SO_KEEPALIVE:
anOptionLevel=SOL_TCP;
break;
}
}
}
TPckgBuf<TIp6Mreq> req;
struct ip_mreq *mreq;
TInt aIndex = -1;
TUint8 *from;
TUint32 srcAddr;
TUint32 maddr;
TInetAddr multiAddr;
TInt *Option = NULL;
TInt ttlValue = 0;
switch(anOptionName)
{
case IP_ADD_MEMBERSHIP: //KSoIp6JoinGroup
case IP_DROP_MEMBERSHIP: //KSoIp6LeaveGroup
mreq = (struct ip_mreq *)anOption.Ptr();
from = (TUint8 *)anOption.Ptr();
from+=4;
// swaping the byte order
srcAddr = ByteOrder::Swap32( mreq->imr_interface.s_addr);
//fetch the interface index
aIndex = GetInterfaceIndex(srcAddr);
// Set the multicast addr
from = (TUint8 *)anOption.Ptr();
maddr=(from[0]<<24)+(from[1]<<16)+(from[2]<<8)+from[3];
multiAddr.SetAddress( maddr);
multiAddr.ConvertToV4Mapped();
if (multiAddr.IsMulticast())
{
req().iAddr = multiAddr.Ip6Address();
req().iInterface = aIndex;
}
ATOMICSOCKETOP( ret = iSocket.SetOpt(anOptionName, anOptionLevel, req), return KErrBadHandle )
return ret;
case IP_MULTICAST_TTL:
anOptionLevel=KSolInetIp;
anOptionName=KSoIp6MulticastHops;
Option = (TInt*)anOption.Ptr();
ttlValue = *Option;
ATOMICSOCKETOP( ret = iSocket.SetOpt(anOptionName,anOptionLevel,ttlValue), return KErrBadHandle )
return ret;
case SO_BROADCAST:
//check if user is trying to disable broadcast
Option = (TInt*)anOption.Ptr();
return (*Option == 0 ? KErrNotSupported : KErrNone);
case IP_MULTICAST_IF:
{
//No support for equivalent flag KsoIp6MulticastIf presently
//call bind instead
struct in_addr *inAddress = (struct in_addr*)anOption.Ptr();
struct sockaddr_in sockAddress;
sockAddress.sin_family = AF_INET;
ATOMICSOCKETOP(sockAddress.sin_port = iSocket.LocalPort();,return KErrBadHandle)
sockAddress.sin_addr.s_addr = inAddress->s_addr;
TUSockAddr ifAddress(&sockAddress, sizeof(sockAddress));
ATOMICSOCKETOP( ret = iSocket.Bind(ifAddress), return KErrBadHandle )
return ret;
}
case IP_MULTICAST_LOOP:
anOptionLevel=KSolInetIp;
anOptionName=KSoIp6MulticastLoop;
break;
}
ATOMICSOCKETOP( ret = iSocket.SetOpt(anOptionName,anOptionLevel,anOption), return KErrBadHandle )
return ret;
}
void CSocketDesc::Sync (TRequestStatus& aStatus)
{
// Judging from the Solaris man pages, this does nothing.
Complete(aStatus,KErrNone);
}
void CSocketDesc::RecvFrom(TDes8& aDesc, TSockAddr& from, int flags, TRequestStatus& aStatus)
{
TInt err = maybe_reopen_socket();
if (err != KErrNone)
{
Complete(aStatus, err);
return;
}
iReadLock.Wait();
CSockDescBase::RecvFrom(aDesc, from, flags, aStatus);
iReadLock.Signal();
}
void CSocketDesc::RecvFromCancel()
{
if (iSocketPtr != NULL)
{
CSockDescBase::RecvFromCancel();
}
}
void CSocketDesc::SendTo(TDes8& aDesc, const struct sockaddr* anAddr, unsigned long aAddrLen, int flags, TRequestStatus& aStatus)
{
TInt err = maybe_reopen_socket();
if (err != KErrNone)
{
Complete(aStatus, err);
return;
}
TUSockAddr toAddr(anAddr, aAddrLen);
iWriteLock.Wait();
CSockDescBase::SendTo(aDesc, toAddr, flags, aStatus);
iWriteLock.Signal();
}
void CSocketDesc::SendToCancel()
{
// Should we use atomic loads here?
if (iSocketPtr != NULL)
{
CSockDescBase::SendToCancel();
}
}
void CSocketDesc::Shutdown(TUint aHow,TRequestStatus& aStatus)
{
if (__e32_atomic_load_acq32(&iSocketPtr) == NULL) // Not opened at all. Nothing to do.
{
Complete(aStatus,KErrNone);
return;
}
CSockDescBase::Shutdown(aHow,aStatus);
return;
}
void CSocketDesc::Accept(CFileDescBase*& aNewSocket, TRequestStatus& aStatus, RSocketServ& aSs, TSockAddr * /*aAddr*/)
{
aNewSocket = NULL;
TInt err = maybe_reopen_socket();
if (err != KErrNone)
{
Complete(aStatus, err);
return;
}
iReadLock.Wait();
// what are the below coverity thingummichs?
//coverity[alloc_fn]
//coverity[assign]
CSocketDesc *newSocket = new CSocketDesc;
if (!newSocket)
{
Complete(aStatus, KErrNoMemory);
iReadLock.Signal();
return;
}
err = newSocket->CreateLock();
if (err)
{
Complete(aStatus, KErrNoMemory);
delete newSocket;
iReadLock.Signal();
//coverity[memory_leak]
return;
}
err = newSocket->iSocket.Open(aSs);
if (err)
{
Complete(aStatus, err);
newSocket->FinalClose(); // this will Close locks
delete newSocket;
iReadLock.Signal();
//coverity[memory_leak]
return;
}
newSocket->iSocketPtr = &newSocket->iSocket;
newSocket->iStyle = iStyle;
err = KErrNone;
ATOMICSOCKETOP( iSocket.Accept(newSocket->iSocket,aStatus), err = KErrBadHandle )
if( err )
{
Complete(aStatus, err);
newSocket->FinalClose(); // this will Close locks
delete newSocket;
}
else
{
aNewSocket = newSocket;
}
iReadLock.Signal();
}
void CSocketDesc::AcceptCancel()
{
if (iSocketPtr != NULL)
{
ATOMICSOCKETOP( iSocket.CancelAccept(), NOP )
}
}
void CSocketDesc::Connect(const struct sockaddr* aAddr,unsigned long size,TRequestStatus& aStatus)
{
TUSockAddr addr(aAddr,size);
if (addr.iError != 0)
{
aStatus = addr.iError;
return;
}
TInt err = maybe_reopen_socket();
if (err != KErrNone)
{
aStatus = err;
return;
}
iWriteLock.Wait();
if( GetConnectionProgress() == EFalse )
{
ATOMICSOCKETOP(iSocket.Connect(addr, aStatus), Complete(aStatus,KErrBadHandle))
User::WaitForRequest(aStatus);
if( aStatus.Int() == KErrWouldBlock )
SetConnectionProgress(ETrue);
}
else
{
aStatus = EALREADY;
}
iWriteLock.Signal();
}
void CSocketDesc::ConnectCancel()
{
if (iSocketPtr != NULL)
{
ATOMICSOCKETOP(iSocket.CancelConnect(),NOP)
}
}
void CSocketDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
{
TInt ret = KErrNone;
int* param = reinterpret_cast<int*>(aParam);
ret = maybe_reopen_socket();
if (ret != KErrNone)
{
Complete(aStatus, ret);
return;
}
switch ((unsigned)aCmd)
{
case FIONREAD:
case E32IONREAD:
{
ATOMICSOCKETOP( ret=iSocket.GetOpt(KSOReadBytesPending,KSOLSocket,*param), ret = KErrBadHandle )
}
break;
case E32IOSELECT:
{
iIoctlBuf.Set((TText8*)aParam,4,4);
iIoctlLock.Wait();
iIoctlFlag = ETrue;
ATOMICSOCKETOP(iSocket.Ioctl(KIOctlSelect,aStatus,&iIoctlBuf,KSOLSocket), Complete(aStatus,KErrBadHandle))
}
return;
case SIOCGIFCONF:
ret = GetInterfaceList(aParam);
break;
case SIOCGIFINDEX:
ret = GetInterfaceIndexByName(aParam);
break;
case SIOCGIFACTIVECONF:
ret = GetActiveInterfaceList(aParam);
break;
case SIOCSIFNAME:
ret = SetInterfaceByName(aParam);
break;
case SIOCIFSTART:
ret = StartInterface(aParam);
if(KErrNone == ret)
{
iSocket.Close();
iSocketPtr = NULL;
}
break;
case SIOCIFACTIVESTART:
ret = StartActiveInterface(aParam);
if(KErrNone == ret)
{
iSocket.Close();
iSocketPtr = NULL;
}
break;
case SIOCIFSTOP:
ret = StopInterface(aParam);
break;
case SIOCATMARK:
ATOMICSOCKETOP(ret=iSocket.GetOpt(KSoTcpRcvAtMark,KSolInetTcp,*param), ret = KErrBadHandle)
break;
case SIOCGIFADDR:
ret = GetIpAddress(aParam);
break;
case SIOCGIFNUM:
ret = GetInterafceNumber(aParam);
break;
case SIOCADDRT:
ret = RouteRequest(KSoInetAddRoute, aParam);
break;
case SIOCDELRT:
ret = RouteRequest(KSoInetDeleteRoute, aParam);
break;
case SIOCGIFHWADDR:
ret = GetInterfaceHWAddress(aParam);
break;
case SIOCGIFACTIVEIAP:
ret = GetActiveInterface( aParam);
break;
default:
ret=KErrNotSupported;
break;
}
Complete(aStatus,ret);
}
TInt CSocketDesc::IoctlCompletion(int /*aCmd*/, void* /*aParam*/, TInt aStatus)
{
if(iIoctlFlag)
{
iIoctlLock.Signal();
iIoctlFlag = EFalse;
}
return aStatus;
}
void CSocketDesc::IoctlCancel()
{
if (iSocketPtr && iIoctlFlag)
{
ATOMICSOCKETOP(iSocket.CancelIoctl(), NOP)
iIoctlLock.Signal();
iIoctlFlag = EFalse;
}
}
// -----------------------------------------------------------------------------
// CSocketDesc::Fcntl
// Symbian Socket Specific Implementation for fcntl
// Implementation of fcntl for Socket will make use of
// RSocket::SetOpt(KSONonBlockingIO/KSOBlockingIO, KSOLSocket)
// As of now fcntl supports F_SETFL and F_GETFL
// -----------------------------------------------------------------------------
//
TInt CSocketDesc::Fcntl(TUint anArg, TUint aCmd)
{
TInt err = maybe_reopen_socket();
if (err != KErrNone)
return err;
return CSockDescBase::Fcntl(anArg, aCmd);
}
TInt CSocketDesc :: GetIpAddress( void *aParam )
{
TInetAddr myAddr;
ATOMICSOCKETOP( iSocket.LocalName(myAddr), return KErrBadHandle )
TUint32 myIP = myAddr.Address();
if (myIP == 0)
{
return KErrGeneral;
}
ifreq *ifr = (ifreq *)aParam;
((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr = myIP;
return KErrNone;
}
TInt CSocketDesc :: GetRemoteIpAddress( void *aParam )
{
TInetAddr remoteAddr;
ATOMICSOCKETOP( iSocket.RemoteName(remoteAddr), return KErrBadHandle )
TUint32 remoteIP = remoteAddr.Address();
if (remoteIP == 0)
{
return KErrGeneral;
}
ifreq *ifr = (ifreq *)aParam;
((struct sockaddr_in *)&ifr->ifr_dstaddr)->sin_addr.s_addr = remoteIP;
return KErrNone;
}
TInt CSocketDesc :: GetInterafceNumber( void *aParam )
{
TInt count = 0;
TInt ret = KErrNone;
TRAP(ret, AccessPointCountL(count));
*(TInt *)aParam = count;
return ret;
}
#ifdef __SYMBIAN_COMPILE_UNUSED__
TInt CSocketDesc :: GetInterafceParamInfo( void *aParam,TInt aType)
{
TInt ret = KErrNone;
TAccessPointRecord tempRecord;
ifreq *ifr = (ifreq *)aParam;
TRAP(ret,FindConnectionInfoL(tempRecord,ifr->ifr_name));
if(ret != KErrNone)
return ret;
wchar_t *str = (wchar_t *)( tempRecord.iServiceType.PtrZ());
TInt servFlag = 0;
if(WcsCmp(str,L"LANService") == 0)
{
servFlag = 0;
}
else if(WcsCmp(str,L"OutgoingGPRS") == 0)
{
servFlag = 1;
}
if(aType == EACCESS_GETMETRIC)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETMETRIC);
}
else if(aType == EACCESS_GETMTU)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETMTU);
}
else if(aType == EACCESS_GETNETMASK)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETNETMASK);
}
else if(aType == EACCESS_GETBROADCAST)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETBROADCAST);
}
else if(aType == EACCESS_GETPHYSADDR)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETPHYSADDR);
}
else if(aType == EACCESS_GETFLAGS)
{
ret = GetInterfaceDetails(aParam,servFlag,EACCESS_GETFLAGS);
}
return ret;
}
TInt CSocketDesc :: SetInterafceParamInfo( void *aParam,TInt aType)
{
TInt ret = KErrNone;
TAccessPointRecord tempRecord;
ifreq *ifr = (ifreq *)aParam;
TRAP(ret,FindConnectionInfoL(tempRecord,ifr->ifr_name));
if(ret != KErrNone)
return ret;
wchar_t *str = (wchar_t *)(tempRecord.iServiceType.PtrZ());
TInt servFlag = 0;
if(WcsCmp(str,L"LANService") == 0)
{
servFlag = 0;
}
else if(WcsCmp(str,L"OutgoingGPRS") == 0)
{
servFlag = 1;
}
if(aType == EACCESS_SETMETRIC)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETMETRIC);
}
else if(aType == EACCESS_SETMTU)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETMTU);
}
else if(aType == EACCESS_SETFLAGS)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETFLAGS);
}
else if(aType == EACCESS_SETPHYSADDR)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETPHYSADDR);
}
else if(aType == EACCESS_SETNETMASK)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETNETMASK);
}
else if(aType == EACCESS_SETBROADCAST)
{
ret = SetInterfaceDetails(aParam,servFlag,EACCESS_SETBROADCAST);
}
return ret;
}
void CSocketDesc::FindConnectionInfoL(TAccessPointRecord &aRecord,char *ptr)
{
//TAccessPointRecord tempRecord;
CCommsDatabase* iapDatabase;
CCommsDbTableView* view;
TInt res;
TPtrC8 tptr((TText8*)ptr);
TBuf<KCommsDbSvrMaxColumnNameLength> temp;
res = CnvUtfConverter::ConvertToUnicodeFromUtf8(temp, tptr);
if(res < KErrNone)
{
User::Leave(res);
}
else if(res > KErrNone)
{
User::Leave(KErrOverflow);
}
// This function can leave on insufficient memory
OpenIapTableLC(&iapDatabase, &view);
res = view->GotoFirstRecord();
while (res == KErrNone)
{
// On error continue with the next record
TRAP( res,ReadRecordFromIapTableL(view, aRecord));
if (res == KErrNone)
{
if(WcsCmp ((wchar_t*)aRecord.iName.PtrZ(),(wchar_t*)temp.PtrZ()) == 0)
break;
}
res = view->GotoNextRecord();
}
CleanupStack::PopAndDestroy();// view
CleanupStack::PopAndDestroy(iapDatabase);
return;
}
TInt CSocketDesc :: SetInterfaceDetails( void *aParam ,TInt aFlag, TInt aType )
{
ifreq *ifr = (ifreq *)aParam;
TPckgBuf<TSoInetIfQuery> ifq;
TBuf8 <25> ipBuf8;
TName aBuf;
TInt ret = KErrNone;
ATOMICSOCKETOP( ret = iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl), ret = KErrBadHandle )
if (ret != KErrNone)
{
return KErrGeneral;
}
TPckgBuf<TSoInet6InterfaceInfo> info;
TSoInet6InterfaceInfo &in = info();
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info), ret = KErrBadHandle )
while(ret == KErrNone)
{
if(info().iName != _L("") && info().iName != _L("loop6") && info().iName != _L("loop4"))
{
TDes16& aName = info().iName;
if( ((aFlag == 0 ) && ( aName.FindC(_L("WLAN")) != KErrNotFound )) ||
((aFlag == 1) && (aName.FindC(_L("Generic")) != KErrNotFound )) )
{
switch(aType)
{
case EACCESS_SETMETRIC:
if(info().iState == EIfUp)
{
info().iSpeedMetric = ifr->ifr_metric;
}
goto setout;
case EACCESS_SETMTU:
if(info().iState == EIfUp)
{
info().iMtu = ifr->ifr_mtu ;
}
goto setout;
case EACCESS_SETNETMASK :
// Presently netmask address is NULL
if((info().iState == EIfUp) && (ifr->ifr_addr.sa_data !=NULL))
{
/*
CharToTBuf8(ifr->ifr_addr.sa_data,ipBuf8);
if (CnvUtfConverter::ConvertToUnicodeFromUtf8( aBuf,ipBuf8 ) == KErrNone)
{
ret = info().iNetMask.Input(aBuf);
}
info().iNetMask.SetAddress(INET_ADDR(255,255,255,0));
*/
return KErrNotSupported;
}
break;
case EACCESS_SETBROADCAST :
if((info().iState == EIfUp) && (ifr->ifr_broadaddr.sa_data !=NULL))
{
/*CharToTBuf8(ifr->ifr_broadaddr.sa_data,ipBuf8);
if (CnvUtfConverter::ConvertToUnicodeFromUtf8( aBuf,ipBuf8 ) == KErrNone)
{
ret = info().iBrdAddr.Input(aBuf);
}
*/
return KErrNotSupported;
}
break;
case EACCESS_SETPHYSADDR :
// Currently no imeplentation is given as KIfHasHardwareAddr is always
// set to 0 for wlan and GPRS
if(info().iFeatures&KIfHasHardwareAddr)
{
return KErrNotSupported;
}
break;
case EACCESS_SETFLAGS :
info().iFeatures = 0;
// Interface UP
if((ifr->ifr_flags & IFF_UP) && (ifr->ifr_flags & IFF_DRV_RUNNING))
{
info().iState = EIfUp;
}
else
{
info().iState = EIfDown;
}
// Loopback
if(ifr->ifr_flags & IFF_LOOPBACK)
{
info().iFeatures |= KIfIsLoopback;
}
// point to point support
if(ifr->ifr_flags & IFF_POINTOPOINT)
{
info().iFeatures |= KIfIsPointToPoint;
}
// Broadcast
if(ifr->ifr_flags & IFF_BROADCAST)
{
info().iFeatures |=KIfCanBroadcast;
}
// Multicast
if(ifr->ifr_flagshigh & IFF_MULTICAST)
{
info().iFeatures = KIfCanMulticast;
}
//these flags details are available in symbian but not used by lib layer.
/* if(info().iFeatures&KIfCanSetMTU)
if(info().iFeatures&KIfHasHardwareAddr)
if(info().iFeatures&KIfCanSetHardwareAddr) */
goto setout;
default:
break;
}
}
}
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info), ret = KErrBadHandle )
}
setout:
TPckgBuf<TSoInet6InterfaceInfo> changeToNew(info());
ATOMICSOCKETOP(ret = iSocket.SetOpt(KSoInetConfigInterface, KSolInetIfCtrl,changeToNew), return KErrBadHandle )
return ret;
}
#endif // __SYMBIAN_COMPILE_UNUSED__
TInt CSocketDesc::GetInterfaceDetails( void *aParam ,TInt aFlag, TInt aType )
{
TPckgBuf<TSoInetIfQuery> ifq;
TInt ret = KErrNone;
ATOMICSOCKETOP( ret = iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl), ret = KErrBadHandle )
if (ret != KErrNone)
{
return KErrGeneral;
}
ifreq *ifr = (ifreq *)aParam;
*(ifr->ifr_addr.sa_data) = '\0';
TPckgBuf<TSoInetInterfaceInfo> info;
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info), ret = KErrBadHandle )
while( ret == KErrNone)
{
if(info().iName != _L("") && info().iName != _L("loop6") && info().iName != _L("loop4"))
{
TDes16& aName = info().iName;
TName aBuf;
TBuf8<KMaxName> ipAddr;
if( ((aFlag == 0 ) && ( aName.FindC(_L("WLAN")) != KErrNotFound )) ||
((aFlag == 1) && (aName.FindC(_L("Generic")) != KErrNotFound )) )
{
switch(aType)
{
case EACTIVE_GETIP :
if((info().iState == EIfUp) && (info().iAddress.Address() != NULL))
{
if(!((info().iAddress.IsLinkLocal()) || (info().iAddress.IsSiteLocal())))
{
info().iAddress.Output(aBuf);
if (CnvUtfConverter::ConvertFromUnicodeToUtf8( ipAddr, aBuf ) == KErrNone)
{
StrlCopy(ifr->ifr_addr.sa_data,(const char *) ipAddr.PtrZ(),ipAddr.Length()+1);
}
}
}
break;
case EACCESS_GETMETRIC:
ifr->ifr_metric = 0;
if (info().iState == EIfUp)
{
ifr->ifr_metric = info().iSpeedMetric;
}
break;
case EACCESS_GETMTU:
ifr->ifr_mtu = 0;
if (info().iState == EIfUp)
{
ifr->ifr_mtu = info().iMtu;
}
break;
case EACCESS_GETNETMASK :
*(ifr->ifr_addr.sa_data) = '\0';
// Presently netmask address is NULL
if((info().iState == EIfUp) && (info().iNetMask.Address() != NULL))
{
//anAddr = info().iNetMask.Address();
info().iNetMask.Output(aBuf);
if (CnvUtfConverter::ConvertFromUnicodeToUtf8( ipAddr, aBuf ) == KErrNone)
{
StrlCopy(ifr->ifr_addr.sa_data,(const char *) ipAddr.PtrZ(),ipAddr.Length()+1);
}
}
break;
case EACCESS_GETBROADCAST :
*(ifr->ifr_broadaddr.sa_data) = '\0';
// Presently Breaodcast address is NULL
if((info().iState == EIfUp) && (info().iBrdAddr.Address() != NULL))
{
//anAddr = info().iBrdAddr.Address();
info().iBrdAddr.Output(aBuf);
if (CnvUtfConverter::ConvertFromUnicodeToUtf8( ipAddr, aBuf ) == KErrNone)
{
StrlCopy(ifr->ifr_broadaddr.sa_data,(const char *) ipAddr.PtrZ(),ipAddr.Length()+1);
}
}
break;
case EACCESS_GETPHYSADDR :
ifr->ifr_phys = 0;
// Currently no imeplentation is given as KIfHasHardwareAddr is always
// set to 0 for wlan and GPRS
if(info().iFeatures&KIfHasHardwareAddr)
{
//nada.
}
break;
case EACCESS_GETFLAGS :
ifr->ifr_flags = 0;
ifr->ifr_flagshigh=0;
// Interface UP
if(info().iState == EIfUp)
{
ifr->ifr_flags |= IFF_UP;
ifr->ifr_flags |= IFF_DRV_RUNNING;
}
// Loopback
if(info().iFeatures&KIfIsLoopback)
{
ifr->ifr_flags |= IFF_LOOPBACK;
}
// point to point support
if(info().iFeatures&KIfIsPointToPoint)
{
ifr->ifr_flags |= IFF_POINTOPOINT;
}
// Broadcast
if(info().iFeatures&KIfCanBroadcast)
{
ifr->ifr_flags |= IFF_BROADCAST;
}
// Multicast
if(info().iFeatures&KIfCanMulticast)
{
ifr->ifr_flagshigh |= ((IFF_MULTICAST & 0xff00) >> 8);
}
//these flags details are available in symbian but not used by lib layer.
/* if(info().iFeatures&KIfCanSetMTU)
if(info().iFeatures&KIfHasHardwareAddr)
if(info().iFeatures&KIfCanSetHardwareAddr) */
break;
}
}
}
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info), ret = KErrBadHandle )
}
return KErrNone;
}
TInt CSocketDesc::Poll(TPollMode aMode,TBool& aReadyStatus,TInt& aErrno)
{
TInt ret = maybe_reopen_socket();
if (ret != KErrNone)
{
return ret;
}
TInt status;
ATOMICSOCKETOP(ret = iSocket.GetOpt(KSOSelectPoll, KSOLSocket, status), ret = KErrBadHandle)
if (ret == KErrNone)
{
aReadyStatus = status & aMode;
}
return MapError(ret, aErrno);
}
/* The synchronous - non-blocking Poll */
TInt CSocketDesc::Poll(TUint aEvents)
{
TInt err = maybe_reopen_socket();
if (err != KErrNone)
return err;
return CSockDescBase::Poll(aEvents);
}
/* Cancel an outstanding notification request */
void CSocketDesc::CancelNotify()
{
CSockDescBase::CancelNotify();
}
TAccessPointRecord::TAccessPointRecord()
:iId(0),
iName(0),
iDialogPref(ECommDbDialogPrefDoNotPrompt),
iDirection(ECommDbConnectionDirectionUnknown),
iService(0),
iServiceType(0), // Text value
iBearer(0),
iBearerType(0), // Text value
iNetwork(0),
iNetworkWeighting(0),
iLocation(0)
{
}
inline TInt CSocketDesc::GetInterfaceList(void *aParam)
{
return GetInterface(aParam, EACCESS_POINT);
}
TInt CSocketDesc::GetInterfaceIndexByName(void *aParam)
{
ifreq *ifrQuery = (ifreq*)aParam;
ifconf ifc;
// Know how many interfaces
ifc.ifc_len = 0;
ifc.ifc_buf = NULL;
TInt ret = GetInterface(&ifc, EACCESS_POINT);
if (ret != KErrNone)
{
return ret;
}
// Allocate the memory to get the detail interface information
ifc.ifc_buf = (caddr_t)Backend()->Alloc( ifc.ifc_len);
if (ifc.ifc_buf == NULL)
{
return KErrNoMemory;
}
ret = GetInterface(&ifc, EACCESS_POINT);
if (ret != KErrNone)
{
Backend()->Free(ifc.ifc_buf);
return ret;
}
ifreq *ifr = ifc.ifc_req;
TInt ifCount = ifc.ifc_len / sizeof(ifreq);
TInt i = 0;
// We wouldn't need this if we were using a StrNcmp below
ifrQuery->ifr_name[IFNAMSIZ-1] = 0; // don't assume NULL terminated input
// Search for the interface name
for (; i < ifCount; i++, ifr++)
{
if ( StrCmp(ifrQuery->ifr_name, ifr->ifr_name) == 0)
{
ifrQuery->ifr_index = ifr->ifr_index;
break;
}
}
if (i == ifCount)
{
ret = KErrNotFound;
}
Backend()->Free(ifc.ifc_buf);
return ret;
}
inline TInt CSocketDesc::GetActiveInterfaceList(void *aParam)
{
return GetInterface(aParam, EACTIVE_CONNECTION);
}
TInt CSocketDesc::GetInterface(void *aParam, TInt aType)
{
TInt ret = KErrNone;
ifconf *ifc = (ifconf*)aParam;
TInt length = (ifc->ifc_len) / sizeof(ifreq);
TInt count = 0;
// If the length is zero, fill the number of interface information
if ( length <= 0 || ifc->ifc_buf == NULL )
{
if (aType == EACCESS_POINT)
{
TRAP(ret, AccessPointCountL(count));
}
else if (aType == EACTIVE_CONNECTION)
{
ret = ActiveConnectionCount(count);
}
else
{
ret = KErrArgument;
}
if (ret == KErrNone)
{
ifc->ifc_len = sizeof(ifreq) * count;
}
return ret;
}
// length is not 0, read 'length' number of records
CArrayFixFlat<TAccessPointRecord> *apArray;
wchar_t *str;
TInt apIndex;
TInt result = KErrNone;
ifreq *ifr = ifc->ifc_req;
TInt ActiveSet = 0;
// Fixed array of 'length'
apArray = new CArrayFixFlat<TAccessPointRecord>(length);
if (apArray == NULL)
{
return KErrNoMemory;
}
if (aType == EACCESS_POINT)
{
// On return length would contain the number of access points.
TRAP(result, AccessPointListL(apArray, length));
}
else if (aType == EACTIVE_CONNECTION)
{
TRAP(ret, ret=ActiveConnectionListL(apArray, length));
if( ret == KErrNone )
{
TRAP(ret,FindConnectionDetailsL(apArray, length));
ActiveSet = 1;
}
}
if (ret != KErrNone)
{
delete apArray;
return ret;
}
for (apIndex = 0; apIndex < length; apIndex++,ifr++)
{
TAccessPointRecord& ref = (*apArray)[apIndex];
ifr->ifr_name[IFNAMSIZ-1] = 0; // don't assume NULL terminated input
TPtr8 ptr((TText8*)ifr->ifr_name, IFNAMSIZ);
ret = CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, ref.iName);
if(ret == KErrNone)
{
if(ptr.Length() < ptr.MaxLength())
{
ptr.ZeroTerminate();
}
else
{
return KErrOverflow;
}
}
else if (ret > KErrNone)
{
return KErrOverflow;
}
else
{
return ret;
}
// Copy theinterface index
ifr->ifr_index = ref.iId;
if(ActiveSet == 1)
{
str = (wchar_t *)(ref.iServiceType.PtrZ() );
TInt servFlag = 0;
if(WcsCmp(str,L"LANService") == 0)
{
servFlag = 0;
}
else if(WcsCmp(str,L"OutgoingGPRS") == 0)
{
servFlag = 1;
}
GetInterfaceDetails(ifr,servFlag,EACTIVE_GETIP);
}
}
ifc->ifc_len = sizeof(ifreq) * apIndex;
delete apArray;
return KErrNone;
}
TInt CSocketDesc::SetInterfaceByName(void *aParam)
{
ifreq *ifr = (ifreq *)aParam;
if (!ifr)
{
return KErrArgument;
}
ifr->ifr_name[IFNAMSIZ-1] = 0; // don't assume NULL terminated input
TPtrC8 ptr((TText8*)ifr->ifr_name);
TInt ret = CnvUtfConverter::ConvertToUnicodeFromUtf8(iConnPref.iName,ptr);
if(ret > KErrNone )
{
return KErrOverflow;
}
return ret;
}
inline TInt CSocketDesc::StartInterface(void *aParam)
{
return StartConnection(aParam);
}
inline TInt CSocketDesc::StartActiveInterface(void *aParam)
{
return StartSubConnection(aParam);
}
TInt CSocketDesc::StopInterface(void *)
{
if (iConnectionPtr != NULL)
{
StopConnection();
return KErrNone;
}
else if (iSubConnectionPtr != NULL)
{
StopSubConnection();
return KErrNone;
}
return KErrNotFound;
}
TInt CSocketDesc::OpenUsingPreference()
{
TInt ret = 0;
// Update when supporting INET6
TInt addrfamily = (iAddrFamily == AF_INET6 ? KAfInet : iAddrFamily);
if (iConnectionPtr != NULL) // iConnection initialized
{
ret = iSocket.Open(*iSockServPtr,addrfamily,iStyle,iProtocol,iConnection);
}
else if (iSubConnectionPtr != NULL) // iSubConnection initialized
{
ret = iSocket.Open(*iSockServPtr,addrfamily,iStyle,iProtocol,iSubConnection);
}
else
{
RConnection& defConnection = Backend()->GetDefaultConnection();
//Now check if the default connection is intialized. This is given lesser
//priority than the socket specific preferences checked above.
if(defConnection.SubSessionHandle() != 0)
{
ret = iSocket.Open(*iSockServPtr,addrfamily,iStyle,iProtocol,defConnection);
if (!ret)
{
Backend()->AddSocket(this);
}
}
else // No connection preference is set
{
ret = ECONNABORTED;
}
}
if (ret == KErrNone)
{
__e32_atomic_store_rel32(&iSocketPtr, (unsigned long)&iSocket);
}
iConnectInProgress = EFalse;
return ret;
}
void CSocketDesc::TempClose()
{
TUint32 ret = __e32_atomic_ior_ord32((void *)&iCount,0x8000);
if( ret >= 0x8000 )
{
// This indicates a TempClose has already been done from one of the threads
return;
}
// loop and yeild till no more references are held to the iSocket
while( iCount != 0x8000 )
{
// Yeild for 1 ms
User::After(1000);
}
if (iSocket.SubSessionHandle() != 0)
{
iSocketPtr = NULL;
iSocket.CancelAll();
TRequestStatus status;
iSocket.Shutdown(RSocket::EImmediate, status);
User::WaitForRequest(status);
iSocket.Close();
}
}
void CSocketDesc::AccessPointListL(CArrayFixFlat<TAccessPointRecord> *&aRecordPtr,
TInt &aCount)
{
TAccessPointRecord tempRecord;
CCommsDatabase* iapDatabase;
CCommsDbTableView* view;
// This function can leave on insufficient memory
OpenIapTableLC(&iapDatabase, &view);
TInt count = 0;
TInt ret = view->GotoFirstRecord();
while (ret == KErrNone && count < aCount)
{
TRAP(ret, ReadRecordFromIapTableL(view, tempRecord));
if (ret == KErrNone)
{
aRecordPtr->AppendL(tempRecord);
count++;
}
ret = view->GotoNextRecord();
}
CleanupStack::PopAndDestroy();// view
CleanupStack::PopAndDestroy(iapDatabase);
aCount = aRecordPtr->Count();
}
void CSocketDesc::FindConnectionDetailsL(CArrayFixFlat<TAccessPointRecord> *&aRecordPtr,
TInt &aCount)
{
TAccessPointRecord tempRecord;
CCommsDatabase* iapDatabase;
CCommsDbTableView* view;
// This function can leave on insufficient memory
OpenIapTableLC(&iapDatabase, &view);
TInt count = 0;
TInt ret = view->GotoFirstRecord();
while (ret == KErrNone && count < aCount)
{
TRAP(ret, ReadRecordFromIapTableL(view, tempRecord));
if (ret == KErrNone)
{
if((*aRecordPtr)[count].iId == tempRecord.iId )
{
(*aRecordPtr)[count].iServiceType = tempRecord.iServiceType;
ret = view->GotoFirstRecord();
count++;
continue;
}
ret = view->GotoNextRecord();
}
}
CleanupStack::PopAndDestroy();// view
CleanupStack::PopAndDestroy(iapDatabase);
aCount = aRecordPtr->Count();
}
void CSocketDesc::AccessPointCountL(TInt &aCount)
{
CCommsDatabase* iapDatabase;
CCommsDbTableView* view;
OpenIapTableLC(&iapDatabase, &view);
aCount = 0;
TInt ret = view->GotoFirstRecord();
while(ret == KErrNone)
{
aCount++;
ret = view->GotoNextRecord();
}
CleanupStack::PopAndDestroy();// view
CleanupStack::PopAndDestroy(iapDatabase);
}
void CSocketDesc::ReadRecordFromIapTableL(CCommsDbTableView* aView, TAccessPointRecord &aRecord)
{
aView->ReadUintL(TPtrC(COMMDB_ID), aRecord.iId);
aView->ReadTextL(TPtrC(COMMDB_NAME), aRecord.iName);
aRecord.iDialogPref = ECommDbDialogPrefDoNotPrompt;
aView->ReadUintL(TPtrC(IAP_SERVICE), aRecord.iService);
aView->ReadTextL(TPtrC(IAP_SERVICE_TYPE), aRecord.iServiceType);
aView->ReadUintL(TPtrC(IAP_BEARER), aRecord.iBearer);
/*
* IAP_BEARER_TYPE is not a column of IAP table even though its
* listed in header. So not trying to read it.
*/
aView->ReadUintL(TPtrC(IAP_NETWORK), aRecord.iNetwork);
aView->ReadUintL(TPtrC(IAP_NETWORK_WEIGHTING), aRecord.iNetworkWeighting);
aView->ReadUintL(TPtrC(IAP_LOCATION), aRecord.iLocation);
}
void CSocketDesc::OpenIapTableLC(CCommsDatabase **aIapDatabase, CCommsDbTableView **aView)
{
// Get IAP names and ids from the database
*aIapDatabase = CCommsDatabase::NewL(EDatabaseTypeIAP);
CleanupStack::PushL(*aIapDatabase);
(*aIapDatabase)->ShowHiddenRecords();
// This is LC code, that means code has pushed, but not popped
(*aView) = (*aIapDatabase)->OpenTableLC(TPtrC(IAP));
}
inline TInt CSocketDesc::ActiveConnectionCount(TInt &aCount)
{
aCount = ((CFileTable*)iFids)->RConnectionCount();
return KErrNone;
}
TInt CSocketDesc::ActiveConnectionListL(CArrayFixFlat<TAccessPointRecord> *aRecordPtr, TInt &aLength)
{
TInt rcIndex;
RConnection *rc;
TAccessPointRecord tempRecord;
for (rcIndex = 0;rcIndex < aLength; rcIndex++)
{
if ( ((CFileTable*)iFids)->RConnectionAt(rcIndex, rc) != KErrNone )
{
break;
}
// Read index and name of the connection
if ( GetRConnectionDetails(rc, tempRecord) != KErrNone )
{
break;
}
aRecordPtr->AppendL(tempRecord);
}
aLength = aRecordPtr->Count();
return KErrNone;
}
TInt CSocketDesc::GetRConnectionDetails(RConnection *aRc, TAccessPointRecord &aApr)
{
_LIT(KName, "IAP\\Name");
_LIT(KId, "IAP\\Id");
TInt ret = aRc->GetDesSetting(KName, aApr.iName);
if (ret == KErrNone)
{
ret = aRc->GetIntSetting(KId, aApr.iId);
}
return ret;
}
TInt CSocketDesc::StartConnection(void * /* ptr */)
{
if (iConnectionPtr != NULL)
{
return KErrAlreadyExists;
}
TCommDbConnPref connPref;
TInt ret = GetConnectionPreference(connPref);
if (ret != KErrNone)
{
return ret;
}
ret = iConnection.Open(*iSockServPtr);
if (ret != KErrNone)
{
return ret;
}
ret = iConnection.Start(connPref);
if (ret != KErrNone)
{
iConnection.Close();
return ret;
}
iConnectionPtr = &iConnection;
ret = ((CFileTable*)iFids)->AddRConnectionPtr(iConnectionPtr, iRConnectionIndex);
if (ret != KErrNone)
{
iConnection.Close();
iConnectionPtr = NULL;
}
return ret;
}
TInt CSocketDesc::GetConnectionPreference(TCommDbConnPref &aCommPref)
{
if (iConnPref.iName.Length() == 0)
{
return KErrArgument;
}
TAccessPointRecord apr;
TInt ret;
// Connection preference is set
TRAP(ret, GetIapDetailsByNameL(iConnPref.iName, apr));
if (ret == KErrNone)
{
aCommPref.SetIapId(apr.iId);
aCommPref.SetNetId(apr.iNetwork);
aCommPref.SetBearerSet(apr.iBearer);
aCommPref.SetDialogPreference((TCommDbDialogPref)apr.iDialogPref);
aCommPref.SetDirection((TCommDbConnectionDirection)apr.iDirection);
}
return ret;
}
void CSocketDesc::GetIapDetailsByNameL(
TBuf<KCommsDbSvrMaxColumnNameLength> aIapName,
TAccessPointRecord &aRecord)
{
TAccessPointRecord tempRecord;
CCommsDatabase* iapDatabase;
CCommsDbTableView* view;
TInt ret = KErrNotFound;
OpenIapTableLC(&iapDatabase, &view);
ret = view->GotoFirstRecord();
while (ret == KErrNone)
{
TRAP(ret, ReadRecordFromIapTableL(view, tempRecord));
if (ret == KErrNone)
{
if (aIapName == tempRecord.iName)
{
aRecord = tempRecord;
ret = KErrNone;
break;
}
}
ret = view->GotoNextRecord();
}
CleanupStack::PopAndDestroy();// view
CleanupStack::PopAndDestroy(iapDatabase);
if (ret != KErrNone)
{
User::Leave(KErrNotFound);
}
}
void CSocketDesc::StopConnection()
{
iConnection.Close();
iConnectionPtr = NULL;
((CFileTable*)iFids)->RemoveRConnectionPtrAt(iRConnectionIndex);
iRConnectionIndex = -1;
}
void CSocketDesc::StopSubConnection()
{
iSubConnection.Close();
iSubConnectionPtr = NULL;
}
TInt CSocketDesc::StartSubConnection(void *)
{
if (iSubConnectionPtr != NULL)
{
return KErrAlreadyExists;
}
TInt ret = KErrArgument;
TInt rcIndex = 0;
RConnection *rc;
TAccessPointRecord record;
do
{
if (((CFileTable*)iFids)->RConnectionAt(rcIndex, rc) != KErrNone)
{
break;
}
// Read index and name of the connection
GetRConnectionDetails(rc, record);
if (record.iName == iConnPref.iName)
{
ret = KErrNone; // RConnection found
break;
}
rcIndex++;
}
while (ETrue); //Loop over all active connections
if (ret == KErrNone)
{
ret = iSubConnection.Open(*iSockServPtr, RSubConnection::EAttachToDefault, *rc);
if (ret == KErrNone)
{
iSubConnectionPtr = &iSubConnection;
}
}
return ret;
}
inline void CSocketDesc::SetFids(void *aFids)
{
iFids = aFids;
}
//Add an entry in the interface routing table
TInt CSocketDesc::RouteRequest(TInt aReq, void *aParam)
{
struct rtentry* rt=reinterpret_cast<struct rtentry*>(aParam);
if (!rt)
{
return KErrArgument;
}
TInt ret;
TPckgBuf<TSoInetRouteInfo>iroute;
iroute().iType=ERtNormal;
iroute().iState=ERtReady;
iroute().iMetric=rt->rt_metric;
if (rt->rt_dev)
{
TPckgBuf<TSoInetInterfaceInfo> iface;
TFileName name;
name.Copy(TPtrC8((TText8*)rt->rt_dev));
if((ret=GetInterfaceByName(name, iface)) != KErrNone)
return ret;
Copy(iroute().iIfAddr, iface().iAddress);
ConvertRtEntry(iroute(), rt);
//add the entry
ATOMICSOCKETOP( ret = iSocket.SetOpt(aReq, KSolInetRtCtrl, iroute),return KErrBadHandle )
return ret;
}
return KErrUnknown;
}
TInt CSocketDesc::Copy(TInetAddr& aDest, TInetAddr& aSrc)
{
if (aSrc.IsV4Mapped() || aSrc.IsV4Compat())
{
aSrc.ConvertToV4();
}
aDest.SetAddress(aSrc.Address());
aDest.SetFamily(aSrc.Family());
aDest.SetPort(aSrc.Port());
return KErrNone;
}
TInt CSocketDesc::ConvertSockAddr(TInetAddr& aInetAddr, struct sockaddr_in *aSockAddr)
{
if (aSockAddr == NULL)
{
return KErrArgument;
}
//convert the address and port from network to host byte order...
aInetAddr.SetAddress(ByteOrder::Swap32(aSockAddr->sin_addr.s_addr));
aInetAddr.SetFamily(aSockAddr->sin_family);
aInetAddr.SetPort(ByteOrder::Swap16(aSockAddr->sin_port));
return KErrNone;
}
TInt CSocketDesc::ConvertRtEntry(TSoInetRouteInfo& aRouteInfo, struct rtentry *aRouteEntry)
{
if(aRouteEntry == NULL)
{
return KErrArgument;
}
ConvertSockAddr(aRouteInfo.iDstAddr, (struct sockaddr_in *)&aRouteEntry->rt_dst);
ConvertSockAddr(aRouteInfo.iNetMask, (struct sockaddr_in *)&aRouteEntry->rt_genmask);
ConvertSockAddr(aRouteInfo.iGateway, (struct sockaddr_in *)&aRouteEntry->rt_gateway);
return KErrNone;
}
TInt CSocketDesc::GetInterfaceByName(const TDesC& aIfName, TPckgBuf<TSoInetInterfaceInfo>& aIface)
{
TInt ret = KErrNone;
ATOMICSOCKETOP(ret = iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl), ret = KErrBadHandle)
if (ret != KErrNone)
{
return ret;
}
TPckgBuf<TSoInetInterfaceInfo> iface;
ATOMICSOCKETOP(ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, iface), ret = KErrBadHandle)
while(ret == KErrNone)
{
if (!iface().iAddress.IsUnspecified() && iface().iName.CompareF(aIfName) == 0)
{
aIface = iface;
return ret;
}
ATOMICSOCKETOP( ret = iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, iface), ret = KErrBadHandle )
}
return KErrUnknown;
}
TInt CSocketDesc::GetInterfaceHWAddress(void *aParam)
{
ifreq *ifr = reinterpret_cast<ifreq *>(aParam);
if (!ifr)
{
return KErrArgument;
}
if (ifr->ifr_name[0] != '\0')
{
TPckgBuf<TSoInetInterfaceInfo> iface;
TFileName name;
ifr->ifr_name[IFNAMSIZ-1] = 0; // don't assume NULL terminated input
name.Copy(TPtrC8((TText8*)ifr->ifr_name));
TInt ret = GetInterfaceByName(name, iface);
if (ret != KErrNone)
return ret;
if (iface().iHwAddr.Length() > sizeof(SSockAddr))
{
Mem::Copy(&(ifr->ifr_hwaddr.sa_data[0]),&(iface().iHwAddr[sizeof(SSockAddr)]), 6);
ifr->ifr_hwaddr.sa_family = (TUint16)iface().iHwAddr.Family();
ifr->ifr_hwaddr.sa_port = ByteOrder::Swap16(iface().iHwAddr.Port());
return ret;
}
}
return KErrUnknown;
}
//This function retrieves the Currently active IAP ID using the RSocket Query.
//First get the interface index of the active connection using KSoInterfaceIndex
//Then with the help of the interface index, fetch the TSoInetIfQuery, under which iZone
//will contain the snap id. User is supposed to call if_indextoname() api to get the IAP name
//from the ID retured with this Ioctl implementation.
TInt CSocketDesc::GetActiveInterface( void *aParam)
{
TInt ifindex = -1;
TInt ret = KErrNone;
ATOMICSOCKETOP(ret = iSocket.GetOpt(KSoInterfaceIndex, KSolInetIp , ifindex), ret = KErrBadHandle)
if(ret!=KErrNone)
{
return ret;
}
TPckgBuf<TSoInetIfQuery> opt;
opt().iIndex = ifindex;
ATOMICSOCKETOP(ret = iSocket.GetOpt(KSoInetIfQueryByIndex, KSolInetIfQuery, opt), ret = KErrBadHandle)
if(ret!=KErrNone)
{
return ret;
}
ifreq *ifr = (ifreq * )aParam;
ifr->ifr_index = opt().iZone[1]; //IAP_ID
return KErrNone;
}