--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/openenvcore/backend/src/syscall/handlenms.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,748 @@
+/*
+* Copyright (c) 2005-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 "sysreent.h"
+#include <sys/socket.h>
+#include <stdapis/netinet/in.h>
+#include <es_sock.h>
+#include <utf.h>
+
+#include "sysif.h"
+#include "fdesc.h"
+#include "lposix.h"
+
+#include "netdb_r.h"
+
+extern "C" {
+
+EXPORT_C int _socket_r (int *aErrno, int family, int style, int protocol)
+ {
+ return Backend()->socket(family, style, protocol, *aErrno);
+ }
+
+
+EXPORT_C int _recvfrom_r (int *aErrno, int fd, char *buf, size_t nbyte, int flags, struct sockaddr* from, size_t* fromsize)
+ {
+ return Backend()->recvfrom(fd, buf, nbyte, flags, from, (unsigned long*)fromsize, *aErrno);
+ }
+
+EXPORT_C int _sendto_r (int *aErrno, int fd, const char *buf, size_t nbyte, int flags, struct sockaddr* to, size_t tosize)
+ {
+ return Backend()->sendto(fd, buf, nbyte, flags, to, tosize, *aErrno);
+ }
+
+
+EXPORT_C int _shutdown_r (int *aErrno, int fd, int how)
+ {
+ return Backend()->shutdown(fd, how, *aErrno);
+ }
+
+EXPORT_C int _listen_r (int *aErrno, int fd, int n)
+ {
+ return Backend()->listen(fd, n, *aErrno);
+ }
+
+EXPORT_C int _accept_r (int *aErrno, int fd, struct sockaddr *addr, size_t *size)
+ {
+ int newfd = Backend()->accept(fd, addr, size, *aErrno);
+ if (newfd>=0 && (addr != NULL) && (size != NULL))
+ Backend()->sockname(newfd, addr, (unsigned long*)size, 1, *aErrno); // getpeername
+ return newfd;
+ }
+
+EXPORT_C int _bind_r (int *aErrno, int fd,const struct sockaddr *addr, size_t size)
+ {
+ return Backend()->bind(fd, addr, size, *aErrno);
+ }
+
+
+EXPORT_C int _connect_r (int *aErrno, int fd, const struct sockaddr *addr, size_t size)
+ {
+ return Backend()->connect(fd, addr, size, *aErrno);
+ }
+
+EXPORT_C int _getsockname_r (int *aErrno, int fd, struct sockaddr *addr, size_t* size)
+ {
+ if (size == 0)
+ {
+ *aErrno = EINVAL;
+ return -1;
+ }
+
+ return Backend()->sockname(fd, addr, (unsigned long*)size, 0, *aErrno);
+ }
+
+EXPORT_C int _getpeername_r (int *aErrno, int fd, struct sockaddr *addr, size_t* size)
+ {
+ if (size == 0)
+ {
+ *aErrno = EINVAL;
+ return -1;
+ }
+ return Backend()->sockname(fd, addr, (unsigned long*)size, 1, *aErrno);
+ }
+
+EXPORT_C int _getsockopt_r (int *aErrno, int fd, int level, int opt, void* buf, size_t* len)
+ {
+ if (len == 0)
+ {
+ *aErrno = EFAULT;
+ return -1;
+ }
+ return Backend()->getsockopt(fd, level, opt, buf, (unsigned long*)len, *aErrno);
+ }
+
+EXPORT_C int _setsockopt_r (int *aErrno, int fd, int level, int opt, void* buf, size_t len)
+ {
+ return Backend()->setsockopt(fd, level, opt, buf, len, *aErrno);
+ }
+
+LOCAL_C inline TInt SockServConnect(RSocketServ& aSs)
+ {
+ TInt err = aSs.Connect(TUint(-1)); // allow arbit number of requests
+ if (err == KErrNone)
+ {
+ err = aSs.ShareAuto();
+ }
+ return err;
+ }
+
+EXPORT_C int _gethostname_r (int *aErrno, char *name, size_t size)
+ {
+ TInt err = KErrNone;
+ if(size <= 0)
+ {
+ return MapError(EINVAL, *aErrno);
+ }
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ return MapError(err, *aErrno);
+ }
+ }
+
+ RHostResolver hr;
+ /* Get the default RConnection instance and use it if configured.
+ NOTE: This RConnection, if configured, would be created using the
+ socket server on backend. The same server has to be used here */
+ RConnection defConnection = Backend()->GetDefaultConnection();
+ if(defConnection.SubSessionHandle() != 0)
+ {
+ err = hr.Open(ss, AF_INET, IPPROTO_UDP,defConnection);
+ }
+ else
+ {
+ err = hr.Open(ss, AF_INET, IPPROTO_UDP);
+ }
+
+ if (err == KErrNone)
+ {
+ TBuf<128> hostname;
+ err = hr.GetHostName(hostname);
+ if (err == KErrNone)
+ {
+ TPtr8 ret((TText8*)name, size-1);
+ if(CnvUtfConverter::ConvertFromUnicodeToUtf8(ret,hostname) == 0)
+ {
+ name[ret.Size()] = '\0';
+ }
+ else
+ {
+ err = ENAMETOOLONG;
+ }
+
+ }
+ }
+ hr.Close();
+ return MapError(err, *aErrno);
+ }
+
+EXPORT_C int _getprotobyname_r(int* aErrno, const char* name, TProtocolDesc* pProtoInf)
+ {
+ TInt err = KErrNone;
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ return MapError(err, *aErrno);
+ }
+ }
+
+ TBuf<128> buf;
+ TPtrC8 bufPtr((TText8*)name);
+ buf.Copy(bufPtr);
+
+ err = ss.FindProtocol(buf, *pProtoInf);
+ return MapError(err, *aErrno);
+ }
+
+EXPORT_C int _getprotobynumber_r(int *aErrno, int proto, TProtocolDesc* pProtoInf)
+ {
+ TInt err = KErrNone;
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ return MapError(err, *aErrno);
+ }
+ }
+
+ TUint count;
+ err = ss.NumProtocols(count);
+ if (err == KErrNone)
+ {
+ TInt idx = 1;
+ for (; idx <= count; ++idx)
+ {
+ err = ss.GetProtocolInfo(idx, *pProtoInf);
+ if (err != KErrNone || pProtoInf->iProtocol == proto)
+ {
+ break;
+ }
+ }
+
+ if (idx > count)
+ {
+ // no protocol matched input
+ return -1;
+ }
+ }
+ return MapError(err, *aErrno);
+ }
+
+
+struct hostent_buf
+ {
+ struct hostent iHostent;
+ struct sockaddr iAddr;
+ char* iPtrs[2];
+ char iName[1]; // and following bytes
+ };
+
+struct hostent* mapNameRecord(struct _reent* rp, TNameRecord& aRecord, int length, int format)
+ {
+ Backend()->Free(rp->_netdb);
+ HBufC8 * name;
+ TInt errNum;
+ if(ConvertUnicodeToUtf8(aRecord.iName,name,errNum) == -1)
+ {
+ rp->_errno = EINVAL;
+ return 0;
+ }
+
+ // Switch to the backend heap
+ RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
+ struct hostent_buf* hbp = (struct hostent_buf*)Backend()->Alloc(sizeof(struct hostent_buf)+name->Size()+1);
+ // Revert to the default heap
+ User::SwitchHeap(oldHeap);
+
+ rp->_netdb = hbp;
+ if (hbp == 0)
+ {
+ delete name;
+ rp->_errno = ENOMEM;
+ return 0;
+ }
+ hbp->iHostent.h_name = &hbp->iName[0]; // one name
+ hbp->iHostent.h_aliases = &hbp->iPtrs[1]; // no aliases
+ hbp->iHostent.h_addrtype = format;
+ hbp->iHostent.h_length = length;
+ hbp->iHostent.h_addr_list = &hbp->iPtrs[0]; // one address...
+ hbp->iPtrs[0] = (char*)&hbp->iAddr.sa_data[0]; // ... which is iAddr
+
+ TPtr8 tname((TText8*)&hbp->iName[0], name->Size()+1);
+ tname.Copy(name->Des());
+ tname.ZeroTerminate();
+ delete name;
+
+ unsigned long len = sizeof(hbp->iAddr);
+ aRecord.iAddr.SetFamily(format); // not set by GetByName(_L(""));
+ static_cast<TUSockAddr*>(&aRecord.iAddr)->Get(&hbp->iAddr, &len);
+ return &hbp->iHostent;
+ }
+
+/*
+Get the internet name of the host by address.
+@return
+@param rp pointer
+@param addr
+@param length
+@param format
+*/
+EXPORT_C struct hostent* _gethostbyaddr_r (struct _reent* rp, const char* addr, int length, int format)
+ {
+ TInt err = KErrNone;
+ struct hostent* retval = NULL;
+
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ MapError(err, rp->_errno);
+ return retval;
+ }
+ }
+
+ if(format != AF_INET && format != AF_INET6)
+ {
+ format = AF_INET;
+ }
+
+ if (err == KErrNone)
+ {
+ RHostResolver r;
+ /* Get the default RConnection instance and use it if configured.
+ NOTE: This RConnection, if configured, would be created using the
+ socket server on backend. The same server has to be used here */
+ RConnection defConnection = Backend()->GetDefaultConnection();
+ if(defConnection.SubSessionHandle() != 0)
+ {
+ err=r.Open(ss, format, IPPROTO_UDP, defConnection);
+ }
+ else
+ {
+ err=r.Open(ss, format, IPPROTO_UDP);
+ }
+
+ if (err == KErrNone)
+ {
+ struct sockaddr buf;
+ buf.sa_family = (unsigned short)format;
+ memcpy(buf.sa_data,addr,length);
+ TUSockAddr addr(&buf, length+4);
+ TNameRecord record;
+ TNameEntry entry(record);
+ TInetAddr inetAddr(addr);
+
+ if(inetAddr.IsLoopback())
+ {
+ if(format == AF_INET)
+ inetAddr.SetAddress(KInetAddrLoop);
+ else if(format == AF_INET6)
+ inetAddr.SetAddress(KInet6AddrLoop);
+ entry().iAddr = inetAddr;
+ entry().iName.Copy(_L("localhost"));
+ }
+
+ else
+ {
+ err = r.GetByAddress(addr, entry);
+ while (err == KErrNone)
+ {
+ TInetAddr addr(entry().iAddr);
+ if(!addr.IsUnspecified())
+ {
+ if(format == addr.Family())
+ {
+ break;
+ }
+ else if(format == AF_INET && addr.Family() == AF_INET6 && addr.IsV4Mapped())
+ {
+ addr.ConvertToV4();
+ entry().iAddr = addr;
+ break;
+ }
+ }
+ err = r.Next(entry);
+ }
+ }
+ if (err == KErrNone)
+ {
+ record = entry();
+ retval = mapNameRecord(rp, record, length, format);
+ }
+ r.Close();
+ }
+ }
+ if (err == -3004) // NETDIAL busy
+ err = TRY_AGAIN;
+ if (err < -3000) // i.e. a NETDIAL error
+ err = NO_RECOVERY;
+ MapError(err, rp->_errno);
+ return retval;
+ }
+
+/*
+Get the internet name of the host by name.
+@return
+@param rp
+@param name name of the host
+*/
+EXPORT_C struct hostent* _gethostbyname_r (struct _reent* rp, const char* name)
+ {
+ TInt err = KErrNone;
+ struct hostent* retval = NULL;
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ MapError(err, rp->_errno);
+ return retval;
+ }
+ }
+
+ RHostResolver r;
+ /* Get the default RConnection instance and use it if configured.
+ NOTE: This RConnection, if configured, would be created using the
+ socket server on backend. The same server has to be used here */
+ RConnection defConnection = Backend()->GetDefaultConnection();
+ if (defConnection.SubSessionHandle() != 0)
+ {
+ err = r.Open(ss, AF_INET, IPPROTO_UDP, defConnection);
+ }
+ else
+ {
+ err = r.Open(ss, AF_INET, IPPROTO_UDP);
+ }
+
+ if (err == KErrNone)
+ {
+ TNameRecord record;
+ TNameEntry entry(record);
+
+ TPtrC8 ptr(reinterpret_cast<const TUint8*> (name));
+ THostName hostname;
+ hostname.Copy(ptr);
+
+ if (hostname.CompareF(_L("localhost")) == KErrNone)
+ {
+ TInetAddr addr;
+ addr.SetAddress(KInetAddrLoop);
+ entry().iAddr = addr;
+ entry().iName.Copy(hostname);
+ }
+ else
+ {
+ err = r.GetByName(hostname, entry);
+ while (err == KErrNone)
+ {
+ TInetAddr addr(entry().iAddr);
+ if(!addr.IsUnspecified())
+ {
+ if (addr.Family() == KAfInet)
+ {
+ break;
+ }
+
+ if (addr.Family() == KAfInet6 && (addr.IsV4Compat() || addr.IsV4Mapped()))
+ {
+ addr.ConvertToV4();
+ entry().iAddr = addr;
+ break;
+ }
+ }
+ err = r.Next(entry);
+ }
+ }
+
+ if (err == KErrNone)
+ {
+ record = entry();
+ retval = mapNameRecord(rp, record, sizeof(struct in_addr), AF_INET);
+ }
+
+ r.Close();
+ }
+
+ if (err == -3004) // NETDIAL busy
+ err = TRY_AGAIN;
+ if (err < -3000) // i.e. a NETDIAL error
+ err = NO_RECOVERY;
+ MapError(err, rp->_errno);
+ return retval;
+ }
+
+/*
+ * Set the default IAP interface in the backend
+ * @param aErrno The errno to be set
+ * @param aIfReq Pointer to the ifreq structure containing the interface name
+ * @return 0 on success, -1 on failure
+ */
+EXPORT_C int _setdefaultif_r(int *aErrno, const struct ifreq* aIfReq)
+ {
+ TInt err = KErrNone;
+
+ RSocketServ& ss = Backend()->SockServSession();
+ // connect to the Socket Server if necessary
+ //NOTE: The following is not really threadsafe. The checking for the
+ //server handle and connecting to the same should be atomic, and should
+ //be done everywhere else too
+ if (ss.Handle() == 0)
+ {
+ err = SockServConnect(ss);
+ if (err != KErrNone)
+ {
+ MapError(err, *aErrno);
+ return -1;
+ }
+ }
+
+ err = Backend()->setdefaultif(aIfReq);
+ if(err != KErrNone)
+ {
+ MapError(err, *aErrno);
+ return -1;
+ }
+
+ return 0;
+ }
+
+/*
+ * Helper function to create an addrinfo node and fill it.
+ * @param aRec The name details to be used to fill the addrinfo node
+ * @param aHints The hints to be used
+ * @param aNode Pointer to the addrinfo structure pointer to be created
+ * @return 0 on success, EAI_MEMORY on error
+ */
+static int CreateAddrInfoNode(TNameRecord& aRec, const struct addrinfo* aHints, struct addrinfo** aNode)
+ {
+ unsigned long addrLen = 0;
+ TUint nameLen = aRec.iName.Length();
+
+ //The following alloc function fills the chunk with zeros
+ *aNode = (struct addrinfo*) Backend()->Alloc(sizeof(struct addrinfo));
+ if(*aNode == NULL)
+ return EAI_MEMORY;
+
+ //Copy the canonical name
+ if(nameLen != 0 || (aHints->ai_flags & AI_CANONNAME))
+ {
+ (*aNode)->ai_canonname = (char*) Backend()->Alloc(nameLen + 1);
+ if((*aNode)->ai_canonname == NULL)
+ {
+ Backend()->Free(*aNode);
+ *aNode = NULL;
+ return EAI_MEMORY;
+ }
+
+ TPtr8 namePtr((TText8*) (*aNode)->ai_canonname, nameLen + 1);
+#ifdef _UNICODE
+ CnvUtfConverter::ConvertFromUnicodeToUtf8(namePtr, aRec.iName); //wchar* string
+#else
+ namePtr.Copy(aRec.iName); //char* string
+#endif /* _UNICODE */
+ namePtr.ZeroTerminate();
+ }
+
+ TInetAddr inetAddr(aRec.iAddr);
+ (*aNode)->ai_family = inetAddr.Family();
+
+ //Copy the address
+ (*aNode)->ai_addr = (struct sockaddr*) Backend()->Alloc(sizeof(struct sockaddr));
+ if((*aNode)->ai_addr == NULL)
+ {
+ if((*aNode)->ai_canonname != NULL)
+ Backend()->Free((*aNode)->ai_canonname);
+ Backend()->Free(*aNode);
+ *aNode = NULL;
+ return EAI_MEMORY;
+ }
+
+ addrLen = sizeof((*aNode)->ai_addr);
+ STATIC_CAST(TUSockAddr*, &aRec.iAddr)->Get((*aNode)->ai_addr, &addrLen);
+ (*aNode)->ai_addrlen = addrLen;
+
+ return 0;
+ }
+
+/*
+ * Get the list of addresses (in the form of addrinfo structure) by
+ * resolving the given host name. This function returns only
+ * the adresses and the canonical names
+ * @param aErrno Pointer to errno
+ * @param aHostName The host name to be resolved
+ * @param aHints Pointer to the hints structure
+ * @param aRes The pointer to store the result
+ * @return 0 on success, error code on failure
+ */
+EXPORT_C int _getaddrinfo_r(int* aErrno, const char* aHostName,
+ const struct addrinfo* aHints, struct addrinfo** aRes)
+ {
+ TInt err = KErrNone;
+
+ //Check params
+ if(!aHostName || !aHints || !aRes)
+ return EAI_FAIL;
+
+#ifdef _UNICODE
+ TPtrC8 hNamePtr(REINTERPRET_CAST(const TUint8*, aHostName));
+ TBuf<0x40> hostName;
+ hostName.Copy(hNamePtr);
+#else
+ TPtrC8 hostName(REINTERPRET_CAST(const TUint8*, aHostName));
+#endif /* _UNICODE */
+
+ //Check for 'localhost'.
+ TBuf<64> localHostName;
+ _LIT(KNameBuf, "localhost");
+ localHostName.Copy(KNameBuf);
+ if(hostName.CompareF(localHostName) == 0 && aHints->ai_family == AF_INET)
+ {
+ TInetAddr localAddr;
+ TNameRecord nameRec;
+ localAddr.SetAddress(INET_ADDR(127, 0, 0, 1));
+ nameRec.iAddr = localAddr;
+ nameRec.iName.Copy(localHostName);
+
+ return CreateAddrInfoNode(nameRec, aHints, aRes);
+ }
+
+ // connect to the Socket Server if necessary
+ RSocketServ& sockServ = Backend()->SockServSession();
+ if (sockServ.Handle() == 0)
+ {
+ err = SockServConnect(sockServ);
+ if (err != KErrNone)
+ {
+ MapError(err, *aErrno);
+ return EAI_SYSTEM;
+ }
+ }
+
+ //Open the host resolver
+ RHostResolver resolver;
+ /* Get the default RConnection instance and use it if configured.
+ NOTE: This RConnection, if configured, would be created using the
+ socket server on backend. The same server has to be used here */
+ RConnection defConnection = Backend()->GetDefaultConnection();
+ if(defConnection.SubSessionHandle() != 0)
+ err = resolver.Open(sockServ, KAfInet, KProtocolInetUdp, defConnection);
+ else
+ err = resolver.Open(sockServ, KAfInet, KProtocolInetUdp);
+
+ if (err != KErrNone)
+ {
+ MapError(err, *aErrno);
+ return EAI_SYSTEM;
+ }
+
+ //Resolve by name
+ TNameRecord nameRec;
+ TNameEntry nameEntry(nameRec);
+
+ err = resolver.GetByName(hostName, nameEntry);
+ if( err != KErrNone)
+ {
+ resolver.Close();
+ return EAI_FAIL;
+ }
+
+ //Create a list of addrinfo nodes from the result
+ *aRes = NULL;
+ struct addrinfo** curr = aRes;
+ do
+ {
+ nameRec = nameEntry();
+ TInetAddr inetAddr(nameRec.iAddr);
+ //Create the node if the address is valid, and the family matches that of hints
+ if(!inetAddr.IsUnspecified())
+ {
+ if (inetAddr.Family() == KAfInet)
+ {
+ err = CreateAddrInfoNode(nameRec, aHints, curr);
+ }
+ else if (inetAddr.Family() == KAfInet6)
+ {
+ err = CreateAddrInfoNode(nameRec, aHints, curr);
+ if (err != 0)
+ break;
+
+ curr = &((*curr)->ai_next);
+ if (inetAddr.IsV4Mapped())
+ {
+ inetAddr.ConvertToV4();
+ nameRec.iAddr = inetAddr;
+ err = CreateAddrInfoNode(nameRec, aHints, curr);
+
+ if(err != 0)
+ break;
+
+ if (err == 0)
+ {
+ (*curr)->ai_flags |= AI_V4MAPPED;
+ curr = &((*curr)->ai_next);
+ }
+ }
+ }
+ }
+ err = resolver.Next(nameEntry); //Get the next record
+ if(err != KErrNone)
+ {//No more records. Not an error, just stop iterating
+ err = KErrNone;
+ break;
+ }
+ } while(err == KErrNone);
+
+
+ //If no nodes are created even when the operation is succes, it's an error
+ if(err == 0 && *aRes == NULL)
+ err = -1;
+ //If the operation failed and some nodes are created, free them
+ if(err != 0 && *aRes != NULL)
+ {
+ _freeaddrinfo_r(*aRes);
+ *aRes = NULL;
+ }
+ if(err != 0 && err != EAI_MEMORY)
+ err = EAI_FAIL;
+ resolver.Close();
+ return err;
+ }
+
+/*
+ * Frees the addrinfo structure created in backend
+ * @param aInfo The pointer to the addrinfo structure to be freed
+ */
+EXPORT_C void _freeaddrinfo_r(struct addrinfo* aInfo)
+ {
+ if(aInfo == NULL)
+ return;
+
+ struct addrinfo *next;
+ while(aInfo)
+ {
+ next = aInfo->ai_next;
+ if(aInfo->ai_canonname != NULL)
+ Backend()->Free(aInfo->ai_canonname);
+ if(aInfo->ai_addr != NULL)
+ Backend()->Free(aInfo->ai_addr);
+
+ Backend()->Free(aInfo);
+ aInfo = next;
+ }
+ }
+
+} //extern "C"