summaryrefslogtreecommitdiff
path: root/pjlib/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-12-01 08:52:57 +0000
committerBenny Prijono <bennylp@teluu.com>2007-12-01 08:52:57 +0000
commit2e6a62f43b622320d69971cfc07a68ab59e29f1b (patch)
treee123dbdeb138f64618e9c5bba112798becec5547 /pjlib/src
parent4ee49ed9e7fda6b2150c400cbe5a10dda99867db (diff)
More ticket #415: more IPv6 and some reorganization of the source codes
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1601 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib/src')
-rw-r--r--pjlib/src/pj/addr_resolv_sock.c144
-rw-r--r--pjlib/src/pj/addr_resolv_symbian.cpp217
-rw-r--r--pjlib/src/pj/errno.c3
-rw-r--r--pjlib/src/pj/ioqueue_symbian.cpp84
-rw-r--r--pjlib/src/pj/ip_helper_generic.c38
-rw-r--r--pjlib/src/pj/ip_helper_symbian.cpp133
-rw-r--r--pjlib/src/pj/ip_helper_win32.c111
-rw-r--r--pjlib/src/pj/os_core_symbian.cpp36
-rw-r--r--pjlib/src/pj/os_symbian.h79
-rw-r--r--pjlib/src/pj/sock_bsd.c121
-rw-r--r--pjlib/src/pj/sock_common.c412
-rw-r--r--pjlib/src/pj/sock_symbian.cpp144
12 files changed, 1008 insertions, 514 deletions
diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c
index a4599ef7..aeb61951 100644
--- a/pjlib/src/pj/addr_resolv_sock.c
+++ b/pjlib/src/pj/addr_resolv_sock.c
@@ -55,96 +55,8 @@ PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
return PJ_SUCCESS;
}
-/* Get the default IP interface */
-PJ_DEF(pj_status_t) pj_getdefaultipinterface(pj_in_addr *addr)
-{
- pj_sock_t fd;
- pj_str_t cp;
- pj_sockaddr_in a;
- int len;
- pj_status_t status;
-
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &fd);
- if (status != PJ_SUCCESS) {
- return status;
- }
-
- cp = pj_str("1.1.1.1");
- pj_sockaddr_in_init(&a, &cp, 53);
-
- status = pj_sock_connect(fd, &a, sizeof(a));
- if (status != PJ_SUCCESS) {
- pj_sock_close(fd);
- return status;
- }
-
- len = sizeof(a);
- status = pj_sock_getsockname(fd, &a, &len);
- if (status != PJ_SUCCESS) {
- pj_sock_close(fd);
- return status;
- }
-
- pj_sock_close(fd);
-
- *addr = a.sin_addr;
-
- /* Success */
- return PJ_SUCCESS;
-}
-
-
-/* Resolve the IP address of local machine */
-PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr)
-{
- const pj_str_t *hostname = pj_gethostname();
- struct pj_hostent he;
- pj_status_t status;
-
-
-#ifdef _MSC_VER
- /* Get rid of "uninitialized he variable" with MS compilers */
- pj_bzero(&he, sizeof(he));
-#endif
-
- /* Try with resolving local hostname first */
- status = pj_gethostbyname(hostname, &he);
- if (status == PJ_SUCCESS) {
- *addr = *(pj_in_addr*)he.h_addr;
- }
-
-
- /* If we end up with 127.x.x.x, resolve the IP by getting the default
- * interface to connect to some public host.
- */
- if (status != PJ_SUCCESS || (pj_ntohl(addr->s_addr) >> 24)==127 ||
- addr->s_addr == 0)
- {
- status = pj_getdefaultipinterface(addr);
- }
-
- /* As the last resort, get the first available interface */
- if (status != PJ_SUCCESS) {
- pj_in_addr addrs[2];
- unsigned count = PJ_ARRAY_SIZE(addrs);
-
- status = pj_enum_ip_interface(&count, addrs);
- if (status == PJ_SUCCESS) {
- if (count != 0) {
- *addr = addrs[0];
- } else {
- /* Just return 127.0.0.1 */
- addr->s_addr = pj_htonl (0x7f000001);
- }
- }
- }
-
- return status;
-}
-
-
/* Resolve IPv4/IPv6 address */
-PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af,
+PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
unsigned *count, pj_addrinfo ai[])
{
#if defined(PJ_SOCK_HAS_GETADDRINFO) && PJ_SOCK_HAS_GETADDRINFO!=0
@@ -155,7 +67,8 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af,
PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL);
PJ_ASSERT_RETURN(nodename->ptr && nodename->slen, PJ_EINVAL);
- PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
+ PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 ||
+ af==PJ_AF_UNSPEC, PJ_EINVAL);
/* Copy node name to null terminated string. */
if (nodename->slen >= PJ_MAX_HOSTNAME)
@@ -179,13 +92,10 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af,
if (af!=PJ_AF_UNSPEC && res->ai_family != af)
continue;
- /* Ignore name that's too long */
- len = pj_ansi_strlen(res->ai_canonname);
- if (len >= PJ_MAX_HOSTNAME)
- continue;
-
- /* Store canonical name */
- pj_ansi_strcpy(ai[i].ai_canonname, res->ai_canonname);
+ /* Store canonical name (possibly truncating the name) */
+ pj_ansi_strncpy(ai[i].ai_canonname, res->ai_canonname,
+ sizeof(ai[i].ai_canonname));
+ ai[i].ai_canonname[sizeof(ai[i].ai_canonname)-1] = '\0';
/* Store address */
PJ_ASSERT_ON_FAIL(res->ai_addrlen <= sizeof(pj_sockaddr), continue);
@@ -201,15 +111,43 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af,
return PJ_SUCCESS;
#else /* PJ_SOCK_HAS_GETADDRINFO */
- /* IPv6 is not supported */
- PJ_UNUSED_ARG(nodename);
- PJ_UNUSED_ARG(af);
- PJ_UNUSED_ARG(ai);
PJ_ASSERT_RETURN(count, PJ_EINVAL);
- *count = 0;
- return PJ_EIPV6NOTSUP;
+ if (af == PJ_AF_INET || af == PJ_AF_UNSPEC) {
+ pj_hostent he;
+ unsigned i, max_count;
+ pj_status_t status;
+
+ status = pj_gethostbyname(nodename, &he);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ max_count = *count;
+ *count = 0;
+
+ pj_bzero(ai, max_count * sizeof(pj_addrinfo));
+
+ for (i=0; he.h_addr_list[i] && *count<max_count; ++i) {
+ pj_ansi_strncpy(ai[*count].ai_canonname, he.h_name,
+ sizeof(ai[*count].ai_canonname));
+ ai[*count].ai_canonname[sizeof(ai[*count].ai_canonname)-1] = '\0';
+
+ ai[*count].ai_addr.ipv4.sin_family = PJ_AF_INET;
+ pj_memcpy(&ai[*count].ai_addr.ipv4.sin_addr,
+ he.h_addr_list[i], he.h_length);
+
+ (*count)++;
+ }
+
+ return PJ_SUCCESS;
+
+ } else {
+ /* IPv6 is not supported */
+ *count = 0;
+
+ return PJ_EIPV6NOTSUP;
+ }
#endif /* PJ_SOCK_HAS_GETADDRINFO */
}
diff --git a/pjlib/src/pj/addr_resolv_symbian.cpp b/pjlib/src/pj/addr_resolv_symbian.cpp
index 496c1f8b..d2bc6366 100644
--- a/pjlib/src/pj/addr_resolv_symbian.cpp
+++ b/pjlib/src/pj/addr_resolv_symbian.cpp
@@ -27,12 +27,48 @@
#include "os_symbian.h"
+
// PJLIB API: resolve hostname
PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he)
{
- PJ_ASSERT_RETURN(name && he, PJ_EINVAL);
+ static pj_addrinfo ai;
+ static char *aliases[2];
+ static char *addrlist[2];
+ unsigned count = 1;
+ pj_status_t status;
+
+ status = pj_getaddrinfo(PJ_AF_INET, name, &count, &ai);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ aliases[0] = ai.ai_canonname;
+ aliases[1] = NULL;
+
+ addrlist[0] = (char*) &ai.ai_addr.ipv4.sin_addr;
+ addrlist[1] = NULL;
+
+ pj_bzero(he, sizeof(*he));
+ he->h_name = aliases[0];
+ he->h_aliases = aliases;
+ he->h_addrtype = PJ_AF_INET;
+ he->h_length = 4;
+ he->h_addr_list = addrlist;
+
+ return PJ_SUCCESS;
+}
+
- RHostResolver &resv = PjSymbianOS::Instance()->GetResolver();
+// Resolve for specific address family
+static pj_status_t getaddrinfo_by_af(int af, const pj_str_t *name,
+ unsigned *count, pj_addrinfo ai[])
+{
+ unsigned i;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(name && count && ai, PJ_EINVAL);
+
+ // Get resolver for the specified address family
+ RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(af);
// Convert name to Unicode
wchar_t name16[PJ_MAX_HOSTNAME];
@@ -46,126 +82,81 @@ PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he)
resv.GetByName(data, nameEntry, reqStatus);
User::WaitForRequest(reqStatus);
- if (reqStatus != KErrNone)
- return PJ_RETURN_OS_ERROR(reqStatus.Int());
-
- // Get the resolved TInetAddr
- // This doesn't work, see Martin email on 28/3/2007:
- // const TNameRecord &rec = (const TNameRecord&) nameEntry;
- // TInetAddr inetAddr(rec.iAddr);
- TInetAddr inetAddr(nameEntry().iAddr);
-
- //
- // This where we keep static variables.
- // These should be kept in TLS probably, to allow multiple threads
- // to call pj_gethostbyname() without interfering each other.
- // But again, we don't support threads in Symbian!
- //
- static char resolved_name[PJ_MAX_HOSTNAME];
- static char *no_aliases[1];
- static pj_in_addr *addr_list[2];
- static pj_sockaddr_in resolved_addr;
-
- // Convert the official address to ANSI.
- pj_unicode_to_ansi((const wchar_t*)nameEntry().iName.Ptr(), nameEntry().iName.Length(),
- resolved_name, sizeof(resolved_name));
-
- // Convert IP address
-
- PjSymbianOS::Addr2pj(inetAddr, resolved_addr);
- addr_list[0] = &resolved_addr.sin_addr;
-
- // Return hostent
- he->h_name = resolved_name;
- he->h_aliases = no_aliases;
- he->h_addrtype = pj_AF_INET();
- he->h_length = 4;
- he->h_addr_list = (char**) addr_list;
-
- return PJ_SUCCESS;
-}
-
-
-/* Get the default IP interface */
-PJ_DEF(pj_status_t) pj_getdefaultipinterface(pj_in_addr *addr)
-{
- pj_sock_t fd;
- pj_str_t cp;
- pj_sockaddr_in a;
- int len;
- pj_status_t status;
-
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &fd);
- if (status != PJ_SUCCESS) {
- return status;
- }
-
- cp = pj_str("1.1.1.1");
- pj_sockaddr_in_init(&a, &cp, 53);
-
- status = pj_sock_connect(fd, &a, sizeof(a));
- if (status != PJ_SUCCESS) {
- pj_sock_close(fd);
- return status;
- }
-
- len = sizeof(a);
- status = pj_sock_getsockname(fd, &a, &len);
- if (status != PJ_SUCCESS) {
- pj_sock_close(fd);
- return status;
+ // Iterate each result
+ i = 0;
+ while (reqStatus == KErrNone && i < *count) {
+
+ // Get the resolved TInetAddr
+ TInetAddr inetAddr(nameEntry().iAddr);
+ int addrlen;
+
+ // Ignore if this is not the same address family
+ if (inetAddr.Family() != af) {
+ resv.Next(nameEntry, reqStatus);
+ User::WaitForRequest(reqStatus);
+ continue;
+ }
+
+ // Convert the official address to ANSI.
+ pj_unicode_to_ansi((const wchar_t*)nameEntry().iName.Ptr(),
+ nameEntry().iName.Length(),
+ ai[i].ai_canonname, sizeof(ai[i].ai_canonname));
+
+ // Convert IP address
+ addrlen = sizeof(ai[i].ai_addr);
+ status = PjSymbianOS::Addr2pj(inetAddr, ai[i].ai_addr, &addrlen);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ // Next
+ ++i;
+ resv.Next(nameEntry, reqStatus);
+ User::WaitForRequest(reqStatus);
}
- pj_sock_close(fd);
-
- *addr = a.sin_addr;
-
- /* Success */
+ *count = i;
return PJ_SUCCESS;
}
-
-/* Resolve the IP address of local machine */
-PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr)
+/* Resolve IPv4/IPv6 address */
+PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
+ unsigned *count, pj_addrinfo ai[])
{
- const pj_str_t *hostname = pj_gethostname();
- struct pj_hostent he;
+ unsigned start;
pj_status_t status;
-
-
- /* Try with resolving local hostname first */
- status = pj_gethostbyname(hostname, &he);
- if (status == PJ_SUCCESS) {
- *addr = *(pj_in_addr*)he.h_addr;
+
+ PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC,
+ PJ_EAFNOTSUP);
+ PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL);
+
+ start = 0;
+
+ if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) {
+ unsigned max = *count;
+ status = getaddrinfo_by_af(PJ_AF_INET6, nodename,
+ &max, &ai[start]);
+ if (status == PJ_SUCCESS) {
+ (*count) -= max;
+ start += max;
+ }
}
-
-
- /* If we end up with 127.x.x.x, resolve the IP by getting the default
- * interface to connect to some public host.
- */
- if (status != PJ_SUCCESS || (pj_ntohl(addr->s_addr) >> 24)==127 ||
- addr->s_addr == 0)
- {
- status = pj_getdefaultipinterface(addr);
+
+ if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) {
+ unsigned max = *count;
+ status = getaddrinfo_by_af(PJ_AF_INET, nodename,
+ &max, &ai[start]);
+ if (status == PJ_SUCCESS) {
+ (*count) -= max;
+ start += max;
+ }
}
-
- /* As the last resort, get the first available interface */
- if (status != PJ_SUCCESS) {
- pj_in_addr addrs[2];
- unsigned count = PJ_ARRAY_SIZE(addrs);
-
- status = pj_enum_ip_interface(&count, addrs);
- if (status == PJ_SUCCESS) {
- if (count != 0) {
- *addr = addrs[0];
- } else {
- /* Just return 127.0.0.1 */
- addr->s_addr = pj_htonl(0x7f000001);
- }
- }
+
+ *count = start;
+
+ if (*count) {
+ return PJ_SUCCESS;
+ } else {
+ return status!=PJ_SUCCESS ? status : PJ_ENOTFOUND;
}
-
- return status;
}
-
diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 6de0c922..1b86d4c6 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -71,7 +71,8 @@ static const struct
PJ_BUILD_ERR(PJ_ERESOLVE, "gethostbyname() has returned error"),
PJ_BUILD_ERR(PJ_ETOOSMALL, "Size is too short"),
PJ_BUILD_ERR(PJ_EIGNORED, "Ignored"),
- PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported")
+ PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported"),
+ PJ_BUILD_ERR(PJ_EAFNOTSUP, "Unsupported address family")
};
#endif /* PJ_HAS_ERROR_STRING */
diff --git a/pjlib/src/pj/ioqueue_symbian.cpp b/pjlib/src/pj/ioqueue_symbian.cpp
index 90848f5f..d7aa9d6a 100644
--- a/pjlib/src/pj/ioqueue_symbian.cpp
+++ b/pjlib/src/pj/ioqueue_symbian.cpp
@@ -232,6 +232,10 @@ pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
+ // addrlen must be specified if local or remote is specified
+ PJ_ASSERT_RETURN((!local && !remote) ||
+ (addrlen && *addrlen), PJ_EINVAL);
+
pending_data_.accept_.op_key_ = op_key;
pending_data_.accept_.new_sock_ = new_sock;
pending_data_.accept_.local_ = local;
@@ -254,13 +258,11 @@ pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
//
void CIoqueueCallback::HandleReadCompletion()
{
- if (pending_data_.read_.addr_) {
+ if (pending_data_.read_.addr_ && pending_data_.read_.addrlen_) {
PjSymbianOS::Addr2pj(aAddress_,
- *(pj_sockaddr_in*)pending_data_.read_.addr_);
+ *(pj_sockaddr*)pending_data_.read_.addr_,
+ pending_data_.read_.addrlen_);
pending_data_.read_.addr_ = NULL;
- }
- if (pending_data_.read_.addrlen_) {
- *pending_data_.read_.addrlen_ = sizeof(pj_sockaddr_in);
pending_data_.read_.addrlen_ = NULL;
}
@@ -273,8 +275,10 @@ void CIoqueueCallback::HandleReadCompletion()
//
CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
{
- CPjSocket *pjNewSock = new CPjSocket(blank_sock_);
-
+ CPjSocket *pjNewSock = new CPjSocket(get_pj_socket()->GetAf(),
+ blank_sock_);
+ int addrlen = 0;
+
if (pending_data_.accept_.new_sock_) {
*pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
pending_data_.accept_.new_sock_ = NULL;
@@ -282,26 +286,37 @@ CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
if (pending_data_.accept_.local_) {
TInetAddr aAddr;
- pj_sockaddr_in *ptr_sockaddr;
-
+ pj_sockaddr *ptr_sockaddr;
+
blank_sock_.LocalName(aAddr);
- ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.local_;
- PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
+ ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.local_;
+ addrlen = *pending_data_.accept_.addrlen_;
+ PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
pending_data_.accept_.local_ = NULL;
}
if (pending_data_.accept_.remote_) {
TInetAddr aAddr;
- pj_sockaddr_in *ptr_sockaddr;
+ pj_sockaddr *ptr_sockaddr;
blank_sock_.RemoteName(aAddr);
- ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.remote_;
- PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
+ ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.remote_;
+ addrlen = *pending_data_.accept_.addrlen_;
+ PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen);
pending_data_.accept_.remote_ = NULL;
}
if (pending_data_.accept_.addrlen_) {
- *pending_data_.accept_.addrlen_ = sizeof(pj_sockaddr_in);
+ if (addrlen == 0) {
+ if (pjNewSock->GetAf() == PJ_AF_INET)
+ addrlen = sizeof(pj_sockaddr_in);
+ else if (pjNewSock->GetAf() == PJ_AF_INET6)
+ addrlen = sizeof(pj_sockaddr_in6);
+ else {
+ pj_assert(!"Unsupported address family");
+ }
+ }
+ *pending_data_.accept_.addrlen_ = addrlen;
pending_data_.accept_.addrlen_ = NULL;
}
@@ -605,13 +620,18 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
const pj_sockaddr_t *addr,
int addrlen )
{
- PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
-
+ pj_status_t status;
+
RSocket &rSock = key->cbObj->get_pj_socket()->Socket();
TInetAddr inetAddr;
- PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
TRequestStatus reqStatus;
+ // Convert address
+ status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
+ inetAddr);
+ if (status != PJ_SUCCESS)
+ return status;
+
// We don't support async connect for now.
PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT);
@@ -674,9 +694,22 @@ PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
pj_sockaddr_t *addr,
int *addrlen)
{
+ CPjSocket *sock = key->cbObj->get_pj_socket();
+
+ // If address is specified, check that the length match the
+ // address family
+ if (addr || addrlen) {
+ PJ_ASSERT_RETURN(addr && addrlen && *addrlen, PJ_EINVAL);
+ if (sock->GetAf() == PJ_AF_INET) {
+ PJ_ASSERT_RETURN(*addrlen >= sizeof(pj_sockaddr_in), PJ_EINVAL);
+ } else if (sock->GetAf() == PJ_AF_INET6) {
+ PJ_ASSERT_RETURN(*addrlen >= sizeof(pj_sockaddr_in6), PJ_EINVAL);
+ }
+ }
+
// If socket has reader, delete it.
- if (key->cbObj->get_pj_socket()->Reader())
- key->cbObj->get_pj_socket()->DestroyReader();
+ if (sock->Reader())
+ sock->DestroyReader();
if (key->cbObj->IsActive())
return PJ_EBUSY;
@@ -736,20 +769,23 @@ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
TPtrC8 aBuffer;
TInetAddr inetAddr;
TSockXfrLength aLen;
+ pj_status_t status;
PJ_UNUSED_ARG(op_key);
// Forcing pending operation is not supported.
PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
- // Must be pj_sockaddr_in for now.
- PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
-
+ // Convert address
+ status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen,
+ inetAddr);
+ if (status != PJ_SUCCESS)
+ return status;
+
// Clear flag
flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
aBuffer.Set((const TUint8*)data, (TInt)*length);
- PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
CPjSocket *pjSock = key->cbObj->get_pj_socket();
pjSock->Socket().SendTo(aBuffer, inetAddr, flags, reqStatus, aLen);
diff --git a/pjlib/src/pj/ip_helper_generic.c b/pjlib/src/pj/ip_helper_generic.c
index a9284807..8a2ea785 100644
--- a/pjlib/src/pj/ip_helper_generic.c
+++ b/pjlib/src/pj/ip_helper_generic.c
@@ -23,8 +23,9 @@
#include <pj/string.h>
#include <pj/compat/socket.h>
-static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt,
- pj_in_addr ifs[])
+static pj_status_t dummy_enum_ip_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
{
pj_status_t status;
@@ -33,7 +34,7 @@ static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt,
pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
/* Just get one default route */
- status = pj_getdefaultipinterface(&ifs[0]);
+ status = pj_getdefaultipinterface(af, &ifs[0]);
if (status != PJ_SUCCESS)
return status;
@@ -42,8 +43,9 @@ static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt,
}
#ifdef SIOCGIFCONF
-static pj_status_t sock_enum_ip_interface(unsigned *p_cnt,
- pj_in_addr ifs[])
+static pj_status_t sock_enum_ip_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
{
pj_sock_t sock;
char buf[512];
@@ -52,7 +54,9 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt,
int i, count;
pj_status_t status;
- status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
+ PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
+
+ status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock);
if (status != PJ_SUCCESS)
return status;
@@ -78,7 +82,12 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt,
*p_cnt = count;
for (i=0; i<count; ++i) {
struct ifreq *itf = &ifr[i];
- ifs[i].s_addr = ((struct sockaddr_in *)&itf->ifr_addr)->sin_addr.s_addr;
+ struct sockaddr *ad = itf->ifr_addr;
+
+ ifs[i].addr.sa_family = ad->sa_family;
+ pj_memcpy(pj_sockaddr_get_addr(&ifs[i]),
+ pj_sockaddr_get_addr(ad),
+ pj_sockaddr_get_addr_len(ad));
}
return PJ_SUCCESS;
@@ -88,14 +97,15 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt,
/*
* Enumerate the local IP interface currently active in the host.
*/
-PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
- pj_in_addr ifs[])
+PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
{
#ifdef SIOCGIFCONF
- if (sock_enum_ip_interface(p_cnt, ifs) == PJ_SUCCESS)
+ if (sock_enum_ip_interface(af, p_cnt, ifs) == PJ_SUCCESS)
return PJ_SUCCESS;
#endif
- return dummy_enum_ip_interface(p_cnt, ifs);
+ return dummy_enum_ip_interface(af, p_cnt, ifs);
}
/*
@@ -104,6 +114,7 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
pj_ip_route_entry routes[])
{
+ pj_sockaddr itf;
pj_status_t status;
PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL);
@@ -111,10 +122,11 @@ PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
/* Just get one default route */
- status = pj_getdefaultipinterface(&routes[0].ipv4.if_addr);
+ status = pj_getdefaultipinterface(PJ_AF_INET, &itf);
if (status != PJ_SUCCESS)
return status;
-
+
+ routes[0].ipv4.if_addr.s_addr = itf.ipv4.sin_addr.s_addr;
routes[0].ipv4.dst_addr.s_addr = 0;
routes[0].ipv4.mask.s_addr = 0;
*p_cnt = 1;
diff --git a/pjlib/src/pj/ip_helper_symbian.cpp b/pjlib/src/pj/ip_helper_symbian.cpp
new file mode 100644
index 00000000..3cd2ebfd
--- /dev/null
+++ b/pjlib/src/pj/ip_helper_symbian.cpp
@@ -0,0 +1,133 @@
+/* $Id$ */
+/*
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/ip_helper.h>
+#include <pj/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+
+
+#include "os_symbian.h"
+
+static pj_status_t rsock_enum_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
+{
+ TInt rc;
+ RSocket rSock;
+ TPckgBuf<TSoInetInterfaceInfo> info;
+ unsigned i;
+
+ if (PjSymbianOS::Instance()->Connection()) {
+
+ rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
+ af, PJ_SOCK_DGRAM, KProtocolInetUdp,
+ *PjSymbianOS::Instance()->Connection());
+ } else {
+
+ rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(),
+ af, PJ_SOCK_DGRAM, KProtocolInetUdp);
+
+ }
+
+ if (rc != KErrNone)
+ return PJ_RETURN_OS_ERROR(rc);
+
+ rSock.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+
+ for (i=0; i<*p_cnt &&
+ rSock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl,
+ info) == KErrNone; )
+ {
+ TInetAddr &iAddress = info().iAddress;
+ int namelen;
+
+ if (iAddress.Family() != af) {
+ continue;
+ }
+
+ namelen = sizeof(ifs[i]);
+ if (PjSymbianOS::Addr2pj(iAddress, ifs[i], &namelen) != PJ_SUCCESS)
+ continue;
+
+ ++i;
+ }
+
+ rSock.Close();
+
+ // Done
+ *p_cnt = i;
+
+ return PJ_SUCCESS;
+
+on_error:
+ rSock.Close();
+ *p_cnt = 0;
+ return PJ_RETURN_OS_ERROR(rc);
+}
+
+/*
+ * Enumerate the local IP interface currently active in the host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
+{
+ unsigned start;
+ pj_status_t status = PJ_SUCCESS;
+
+ start = 0;
+
+ /* Get IPv6 interface first. */
+ if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) {
+ unsigned max = *p_cnt;
+ status = rsock_enum_interface(PJ_AF_INET6, &max, &ifs[start]);
+ if (status == PJ_SUCCESS) {
+ (*p_cnt) -= max;
+ start += max;
+ }
+ }
+
+ /* Get IPv4 interface. */
+ if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) {
+ unsigned max = *p_cnt;
+ status = rsock_enum_interface(PJ_AF_INET, &max, &ifs[start]);
+ if (status == PJ_SUCCESS) {
+ (*p_cnt) -= max;
+ start += max;
+ }
+ }
+
+ *p_cnt = start;
+
+ return start ? PJ_SUCCESS : PJ_ENOTFOUND;
+}
+
+/*
+ * Enumerate the IP routing table for this host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
+ pj_ip_route_entry routes[])
+{
+ PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL);
+ *p_cnt = 0;
+ return PJ_ENOTSUP;
+}
+
diff --git a/pjlib/src/pj/ip_helper_win32.c b/pjlib/src/pj/ip_helper_win32.c
index 1a937d72..d5cc9690 100644
--- a/pjlib/src/pj/ip_helper_win32.c
+++ b/pjlib/src/pj/ip_helper_win32.c
@@ -27,6 +27,12 @@
#if defined(_MSC_VER) && _MSC_VER==1200 && !defined(PJ_WIN32_WINCE)
# define PMIB_ICMP_EX void*
#endif
+#include <winsock2.h>
+
+/* If you encounter error "Cannot open include file: 'Iphlpapi.h' here,
+ * you need to install newer Platform SDK. Presumably you're using
+ * Microsoft Visual Studio 6?
+ */
#include <Iphlpapi.h>
#include <pj/ip_helper.h>
@@ -41,6 +47,13 @@
typedef DWORD (WINAPI *PFN_GetIpAddrTable)(PMIB_IPADDRTABLE pIpAddrTable,
PULONG pdwSize,
BOOL bOrder);
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+typedef DWORD (WINAPI *PFN_GetAdapterAddresses)(ULONG Family,
+ ULONG Flags,
+ PVOID Reserved,
+ PIP_ADAPTER_ADDRESSES AdapterAddresses,
+ PULONG SizePointer);
+#endif /* PJ_HAS_IPV6 */
typedef DWORD (WINAPI *PFN_GetIpForwardTable)(PMIB_IPFORWARDTABLE pIpForwardTable,
PULONG pdwSize,
BOOL bOrder);
@@ -48,15 +61,23 @@ typedef DWORD (WINAPI *PFN_GetIfEntry)(PMIB_IFROW pIfRow);
static HANDLE s_hDLL;
static PFN_GetIpAddrTable s_pfnGetIpAddrTable;
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+ static PFN_GetAdapterAddresses s_pfnGetAdapterAddresses;
+#endif /* PJ_HAS_IPV6 */
static PFN_GetIpForwardTable s_pfnGetIpForwardTable;
static PFN_GetIfEntry s_pfnGetIfEntry;
+
static void unload_iphlp_module(void)
{
FreeLibrary(s_hDLL);
s_hDLL = NULL;
s_pfnGetIpAddrTable = NULL;
s_pfnGetIpForwardTable = NULL;
+ s_pfnGetIfEntry = NULL;
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+ s_pfnGetAdapterAddresses = NULL;
+#endif
}
static FARPROC GetIpHlpApiProc(pj_char_t *lpProcName)
@@ -90,6 +111,26 @@ static DWORD MyGetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable,
return ERROR_NOT_SUPPORTED;
}
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+static DWORD MyGetAdapterAddresses(ULONG Family,
+ ULONG Flags,
+ PVOID Reserved,
+ PIP_ADAPTER_ADDRESSES AdapterAddresses,
+ PULONG SizePointer)
+{
+ if(NULL == s_pfnGetAdapterAddresses) {
+ s_pfnGetAdapterAddresses = (PFN_GetAdapterAddresses)
+ GetIpHlpApiProc(PJ_T("GetAdapterAddresses"));
+ }
+
+ if(NULL != s_pfnGetAdapterAddresses) {
+ return s_pfnGetAdapterAddresses(Family, Flags, Reserved,
+ AdapterAddresses, SizePointer);
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+#endif /* PJ_HAS_IPV6 */
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
static DWORD MyGetIfEntry(MIB_IFROW *pIfRow)
@@ -124,11 +165,11 @@ static DWORD MyGetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable,
return ERROR_NOT_SUPPORTED;
}
-/*
- * Enumerate the local IP interface currently active in the host.
+/* Enumerate local IP interface using GetIpAddrTable()
+ * for IPv4 addresses only.
*/
-PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
- pj_in_addr ifs[])
+static pj_status_t enum_ipv4_interface(unsigned *p_cnt,
+ pj_sockaddr ifs[])
{
/* Provide enough buffer or otherwise it will fail with
* error 22 ("Not Enough Buffer") error.
@@ -159,7 +200,7 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
for (i=0; i<count; ++i) {
MIB_IFROW ifRow;
- /* Some Windows returns 0.0.0.0! */
+ /* Ignore 0.0.0.0 address (interface is down?) */
if (pTab->table[i].dwAddr == 0)
continue;
@@ -174,14 +215,72 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
continue;
#endif
- ifs[*p_cnt].s_addr = pTab->table[i].dwAddr;
+ ifs[*p_cnt].ipv4.sin_family = PJ_AF_INET;
+ ifs[*p_cnt].ipv4.sin_addr.s_addr = pTab->table[i].dwAddr;
(*p_cnt)++;
}
return PJ_SUCCESS;
+}
+
+
+/* Enumerate local IP interface using GetAdapterAddresses(),
+ * which works for both IPv4 and IPv6.
+ */
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+static pj_status_t enum_ipv4_ipv6_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
+{
+ pj_uint8_t buffer[1024];
+ IP_ADAPTER_ADDRESSES *adapter = (IP_ADAPTER_ADDRESSES*)buffer;
+ ULONG size = sizeof(buffer);
+ unsigned i;
+ DWORD rc;
+
+ rc = MyGetAdapterAddresses(af, 0, NULL, adapter, &size);
+ if (rc != ERROR_SUCCESS)
+ return PJ_RETURN_OS_ERROR(rc);
+
+ for (i=0; i<*p_cnt && adapter; ++i, adapter = adapter->Next) {
+ SOCKET_ADDRESS *pAddr = &adapter->FirstUnicastAddress->Address;
+ ifs[i].addr.sa_family = pAddr->lpSockaddr->sa_family;
+ pj_memcpy(&ifs[i], pAddr->lpSockaddr, pAddr->iSockaddrLength);
+ }
+ return PJ_SUCCESS;
}
+#endif
+
+/*
+ * Enumerate the local IP interface currently active in the host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
+{
+ pj_status_t status = -1;
+
+ PJ_ASSERT_RETURN(p_cnt && ifs, PJ_EINVAL);
+ PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC || af==PJ_AF_INET || af==PJ_AF_INET6,
+ PJ_EAFNOTSUP);
+
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+ status = enum_ipv4_ipv6_interface(af, p_cnt, ifs);
+ if (status != PJ_SUCCESS && (af==PJ_AF_INET || af==PJ_AF_UNSPEC))
+ status = enum_ipv4_interface(p_cnt, ifs);
+ return status;
+#else
+ if (af==PJ_AF_INET6)
+ return PJ_EIPV6NOTSUP;
+ else if (af != PJ_AF_INET && af != PJ_AF_UNSPEC)
+ return PJ_EAFNOTSUP;
+
+ status = enum_ipv4_interface(p_cnt, ifs);
+ return status;
+#endif
+}
/*
* Enumerate the IP routing table for this host.
diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp
index f656cb68..c193fb5b 100644
--- a/pjlib/src/pj/os_core_symbian.cpp
+++ b/pjlib/src/pj/os_core_symbian.cpp
@@ -154,7 +154,8 @@ TInt CPjTimeoutTimer::RunError(TInt aError)
PjSymbianOS::PjSymbianOS()
: isSocketServInitialized_(false), isResolverInitialized_(false),
console_(NULL), selectTimeoutTimer_(NULL),
- appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL)
+ appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL),
+ appHostResolver6_(NULL)
{
}
@@ -164,6 +165,7 @@ void PjSymbianOS::SetParameters(pj_symbianos_params *params)
appSocketServ_ = (RSocketServ*) params->rsocketserv;
appConnection_ = (RConnection*) params->rconnection;
appHostResolver_ = (RHostResolver*) params->rhostresolver;
+ appHostResolver6_ = (RHostResolver*) params->rhostresolver6;
}
// Get PjSymbianOS instance
@@ -199,16 +201,29 @@ TInt PjSymbianOS::Initialize()
isSocketServInitialized_ = true;
}
- if (!isResolverInitialized_ && appHostResolver_ == NULL) {
- if (Connection())
- err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream,
- *Connection());
- else
- err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream);
+ if (!isResolverInitialized_) {
+ if (appHostResolver_ == NULL) {
+ if (Connection())
+ err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream,
+ *Connection());
+ else
+ err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream);
+
+ if (err != KErrNone)
+ goto on_error;
+ }
+
+ if (appHostResolver6_ == NULL) {
+ if (Connection())
+ err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream,
+ *Connection());
+ else
+ err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream);
+
+ if (err != KErrNone)
+ goto on_error;
+ }
- if (err != KErrNone)
- goto on_error;
-
isResolverInitialized_ = true;
}
@@ -224,6 +239,7 @@ void PjSymbianOS::Shutdown()
{
if (isResolverInitialized_) {
hostResolver_.Close();
+ hostResolver6_.Close();
isResolverInitialized_ = false;
}
diff --git a/pjlib/src/pj/os_symbian.h b/pjlib/src/pj/os_symbian.h
index 2b14ecd6..f564075f 100644
--- a/pjlib/src/pj/os_symbian.h
+++ b/pjlib/src/pj/os_symbian.h
@@ -19,6 +19,8 @@
#ifndef __OS_SYMBIAN_H__
#define __OS_SYMBIAN_H__
+#include <pj/assert.h>
+#include <pj/errno.h>
#include <pj/sock.h>
#include <pj/os.h>
#include <pj/string.h>
@@ -51,14 +53,20 @@ public:
};
// Construct CPjSocket
- CPjSocket(RSocket &sock)
- : sock_(sock), connected_(false), sockReader_(NULL)
+ CPjSocket(int af, RSocket &sock)
+ : af_(af), sock_(sock), connected_(false), sockReader_(NULL)
{
}
// Destroy CPjSocket
~CPjSocket();
+ // Get address family
+ int GetAf() const
+ {
+ return af_;
+ }
+
// Get the internal RSocket
RSocket& Socket()
{
@@ -91,6 +99,7 @@ public:
void DestroyReader();
private:
+ int af_;
RSocket sock_; // Must not be reference, or otherwise
// it may point to local variable!
bool connected_;
@@ -228,23 +237,57 @@ public:
}
// Convert TInetAddr to pj_sockaddr_in
- static inline void Addr2pj(const TInetAddr & sym_addr,
- pj_sockaddr_in &pj_addr)
+ static inline pj_status_t Addr2pj(const TInetAddr & sym_addr,
+ pj_sockaddr &pj_addr,
+ int *addr_len)
{
- pj_bzero(&pj_addr, sizeof(pj_sockaddr_in));
- pj_addr.sin_family = pj_AF_INET();
- pj_addr.sin_addr.s_addr = pj_htonl(sym_addr.Address());
- pj_addr.sin_port = pj_htons((pj_uint16_t) sym_addr.Port());
+ pj_bzero(&pj_addr, sizeof(pj_sockaddr));
+ pj_addr.addr.sa_family = (pj_uint16_t)sym_addr.Family();
+ if (pj_addr.addr.sa_family == PJ_AF_INET) {
+ PJ_ASSERT_RETURN(*addr_len >= sizeof(pj_sockaddr_in), PJ_ETOOSMALL);
+ pj_addr.ipv4.sin_addr.s_addr = pj_htonl(sym_addr.Address());
+ pj_addr.ipv4.sin_port = pj_htons((pj_uint16_t) sym_addr.Port());
+ *addr_len = sizeof(pj_sockaddr_in);
+ } else if (pj_addr.addr.sa_family == PJ_AF_INET6) {
+ PJ_ASSERT_RETURN(*addr_len >= sizeof(pj_sockaddr_in6), PJ_ETOOSMALL);
+ const TIp6Addr & ip6 = sym_addr.Ip6Address();
+ pj_memcpy(&pj_addr.ipv6.sin6_addr, ip6.u.iAddr8, 16);
+ pj_addr.ipv6.sin6_port = pj_htons((pj_uint16_t) sym_addr.Port());
+ pj_addr.ipv6.sin6_scope_id = pj_htonl(sym_addr.Scope());
+ pj_addr.ipv6.sin6_flowinfo = pj_htonl(sym_addr.FlowLabel());
+ *addr_len = sizeof(pj_sockaddr_in6);
+ } else {
+ pj_assert(!"Unsupported address family");
+ return PJ_EAFNOTSUP;
+ }
+
+ return PJ_SUCCESS;
}
// Convert pj_sockaddr_in to TInetAddr
- static inline void pj2Addr(const pj_sockaddr_in &pj_addr,
- TInetAddr & sym_addr)
+ static inline pj_status_t pj2Addr(const pj_sockaddr &pj_addr,
+ int addrlen,
+ TInetAddr & sym_addr)
{
- sym_addr.Init(KAfInet);
- sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.sin_addr.s_addr));
- sym_addr.SetPort(pj_ntohs(pj_addr.sin_port));
+ if (pj_addr.addr.sa_family == PJ_AF_INET) {
+ PJ_ASSERT_RETURN(addrlen >= sizeof(pj_sockaddr_in), PJ_EINVAL);
+ sym_addr.Init(KAfInet);
+ sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.ipv4.sin_addr.s_addr));
+ sym_addr.SetPort(pj_ntohs(pj_addr.ipv4.sin_port));
+ } else if (pj_addr.addr.sa_family == PJ_AF_INET6) {
+ TIp6Addr ip6;
+
+ PJ_ASSERT_RETURN(addrlen >= sizeof(pj_sockaddr_in6), PJ_EINVAL);
+ pj_memcpy(ip6.u.iAddr8, &pj_addr.ipv6.sin6_addr, 16);
+ sym_addr.Init(KAfInet6);
+ sym_addr.SetAddress(ip6);
+ sym_addr.SetScope(pj_ntohl(pj_addr.ipv6.sin6_scope_id));
+ sym_addr.SetFlowLabel(pj_ntohl(pj_addr.ipv6.sin6_flowinfo));
+ } else {
+ pj_assert(!"Unsupported address family");
+ }
+ return PJ_SUCCESS;
}
@@ -253,9 +296,13 @@ public:
//
// Get RHostResolver instance
- RHostResolver & GetResolver()
+ RHostResolver & GetResolver(int af)
{
- return appHostResolver_ ? *appHostResolver_ : hostResolver_;
+ if (af==PJ_AF_INET6) {
+ return appHostResolver6_ ? *appHostResolver6_ : hostResolver6_;
+ } else {
+ return appHostResolver_ ? *appHostResolver_ : hostResolver_;
+ }
}
@@ -303,6 +350,7 @@ private:
bool isResolverInitialized_;
RHostResolver hostResolver_;
+ RHostResolver hostResolver6_;
CConsoleBase* console_;
@@ -312,6 +360,7 @@ private:
RSocketServ *appSocketServ_;
RConnection *appConnection_;
RHostResolver *appHostResolver_;
+ RHostResolver *appHostResolver6_;
private:
PjSymbianOS();
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index 156ded85..761c03bc 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -123,15 +123,6 @@ const int PJ_MSG_PEEK = MSG_PEEK;
const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
-#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
-# define SET_LEN(addr,len) (((pj_sockaddr_in*)(addr))->sin_zero_len=(len))
-# define RESET_LEN(addr) (((pj_sockaddr_in*)(addr))->sin_zero_len=0)
-#else
-# define SET_LEN(addr,len)
-# define RESET_LEN(addr)
-#endif
-
-
/*
* Convert 16-bit value from network byte order to host byte order.
*/
@@ -221,7 +212,7 @@ PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
{
char tempaddr[PJ_INET6_ADDRSTRLEN];
- PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
+ PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
/* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
@@ -310,7 +301,7 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
*dst = '\0';
- PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
+ PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
/*
@@ -353,7 +344,7 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
addr_str_len = PJ_INET6_ADDRSTRLEN;
} else {
pj_assert(!"Unsupported address family");
- return PJ_EINVAL;
+ return PJ_EAFNOTSUP;
}
#if PJ_NATIVE_STRING_IS_UNICODE
@@ -388,87 +379,6 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
}
/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
- pj_in_addr addr;
-
- pj_inet_aton(cp, &addr);
- return addr;
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
-{
- pj_str_t str = pj_str((char*)cp);
- return pj_inet_addr(&str);
-}
-
-/*
- * Set the IP address of an IP socket address from string address,
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
- const pj_str_t *str_addr)
-{
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
- (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- RESET_LEN(addr);
- addr->sin_family = AF_INET;
- pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
-
- if (str_addr && str_addr->slen) {
- addr->sin_addr = pj_inet_addr(str_addr);
- if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
- pj_hostent he;
- pj_status_t rc;
-
- rc = pj_gethostbyname(str_addr, &he);
- if (rc == 0) {
- addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- } else {
- addr->sin_addr.s_addr = PJ_INADDR_NONE;
- return rc;
- }
- }
-
- } else {
- addr->sin_addr.s_addr = 0;
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or
- * may be a hostname. If hostname is specified, then the function will
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
- const pj_str_t *str_addr,
- pj_uint16_t port)
-{
- PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- RESET_LEN(addr);
- addr->sin_family = PJ_AF_INET;
- pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
- pj_sockaddr_in_set_port(addr, port);
- return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
* Get hostname.
*/
PJ_DEF(const pj_str_t*) pj_gethostname(void)
@@ -490,19 +400,6 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void)
return &hostname;
}
-/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
- pj_sockaddr_in addr;
- const pj_str_t *hostname = pj_gethostname();
-
- pj_sockaddr_in_set_str_addr(&addr, hostname);
- return addr.sin_addr;
-}
-
-
#if defined(PJ_WIN32)
/*
* Create new socket/endpoint for communication and returns a descriptor.
@@ -582,7 +479,7 @@ PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
PJ_CHECK_STACK();
- SET_LEN(&addr, sizeof(pj_sockaddr_in));
+ PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
addr.sin_family = PJ_AF_INET;
pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
addr.sin_addr.s_addr = pj_htonl(addr32);
@@ -624,7 +521,7 @@ PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
else {
- RESET_LEN(addr);
+ PJ_SOCKADDR_RESET_LEN(addr);
return PJ_SUCCESS;
}
}
@@ -640,7 +537,7 @@ PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
else {
- RESET_LEN(addr);
+ PJ_SOCKADDR_RESET_LEN(addr);
return PJ_SUCCESS;
}
}
@@ -726,7 +623,7 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
if (*len < 0)
return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
else {
- RESET_LEN(from);
+ PJ_SOCKADDR_RESET_LEN(from);
return PJ_SUCCESS;
}
}
@@ -820,7 +717,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
if (addr) {
- SET_LEN(addr, *addrlen);
+ PJ_SOCKADDR_SET_LEN(addr, *addrlen);
}
#endif
@@ -831,7 +728,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
if (addr) {
- RESET_LEN(addr);
+ PJ_SOCKADDR_RESET_LEN(addr);
}
#endif
diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c
index 5b629fc2..06aa9411 100644
--- a/pjlib/src/pj/sock_common.c
+++ b/pjlib/src/pj/sock_common.c
@@ -17,6 +17,416 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/sock.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/ip_helper.h>
+#include <pj/os.h>
+#include <pj/addr_resolv.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+
+
+/*
+ * Convert address string with numbers and dots to binary IP address.
+ */
+PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
+{
+ pj_in_addr addr;
+
+ pj_inet_aton(cp, &addr);
+ return addr;
+}
+
+/*
+ * Convert address string with numbers and dots to binary IP address.
+ */
+PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
+{
+ pj_str_t str = pj_str((char*)cp);
+ return pj_inet_addr(&str);
+}
+
+/*
+ * Set the IP address of an IP socket address from string address,
+ * with resolving the host if necessary. The string address may be in a
+ * standard numbers and dots notation or may be a hostname. If hostname
+ * is specified, then the function will resolve the host into the IP
+ * address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr)
+{
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
+ (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+ PJ_SOCKADDR_RESET_LEN(addr);
+ addr->sin_family = AF_INET;
+ pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
+
+ if (str_addr && str_addr->slen) {
+ addr->sin_addr = pj_inet_addr(str_addr);
+ if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
+ pj_hostent he;
+ pj_status_t rc;
+
+ rc = pj_gethostbyname(str_addr, &he);
+ if (rc == 0) {
+ addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ } else {
+ addr->sin_addr.s_addr = PJ_INADDR_NONE;
+ return rc;
+ }
+ }
+
+ } else {
+ addr->sin_addr.s_addr = 0;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/* Set address from a name */
+PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
+ pj_sockaddr *addr,
+ const pj_str_t *str_addr)
+{
+ pj_status_t status;
+
+ if (af == PJ_AF_INET) {
+ return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr);
+ }
+
+ PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
+
+ /* IPv6 specific */
+
+ addr->ipv6.sin6_family = PJ_AF_INET6;
+ PJ_SOCKADDR_RESET_LEN(addr);
+
+ if (str_addr && str_addr->slen) {
+ status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
+ if (status != PJ_SUCCESS) {
+ pj_addrinfo ai;
+ unsigned count = 1;
+
+ status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai);
+ if (status==PJ_SUCCESS) {
+ pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
+ sizeof(pj_sockaddr_in6));
+ }
+ }
+ } else {
+ status = PJ_SUCCESS;
+ }
+
+ return status;
+}
+
+/*
+ * Set the IP address and port of an IP socket address.
+ * The string address may be in a standard numbers and dots notation or
+ * may be a hostname. If hostname is specified, then the function will
+ * resolve the host into the IP address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr,
+ pj_uint16_t port)
+{
+ PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+ PJ_SOCKADDR_RESET_LEN(addr);
+ addr->sin_family = PJ_AF_INET;
+ pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
+ pj_sockaddr_in_set_port(addr, port);
+ return pj_sockaddr_in_set_str_addr(addr, str_addr);
+}
+
+/*
+ * Initialize IP socket address based on the address and port info.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_init(int af,
+ pj_sockaddr *addr,
+ const pj_str_t *cp,
+ pj_uint16_t port)
+{
+ pj_status_t status;
+
+ if (af == PJ_AF_INET) {
+ return pj_sockaddr_in_init(&addr->ipv4, cp, port);
+ }
+
+ /* IPv6 specific */
+ PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
+
+ pj_bzero(addr, sizeof(pj_sockaddr_in6));
+ addr->addr.sa_family = PJ_AF_INET6;
+
+ status = pj_sockaddr_set_str_addr(af, addr, cp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ addr->ipv6.sin6_port = pj_htons(port);
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get first IP address associated with the hostname.
+ */
+PJ_DEF(pj_in_addr) pj_gethostaddr(void)
+{
+ pj_sockaddr_in addr;
+ const pj_str_t *hostname = pj_gethostname();
+
+ pj_sockaddr_in_set_str_addr(&addr, hostname);
+ return addr.sin_addr;
+}
+
+/*
+ * Get port number of a pj_sockaddr_in
+ */
+PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
+{
+ return pj_ntohs(addr->sin_port);
+}
+
+/*
+ * Get the address part
+ */
+PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr)
+{
+ const pj_sockaddr *a = (const pj_sockaddr*)addr;
+
+ PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
+ a->addr.sa_family == PJ_AF_INET6, NULL);
+
+ if (a->addr.sa_family == PJ_AF_INET6)
+ return (void*) &a->ipv6.sin6_addr;
+ else
+ return (void*) &a->ipv4.sin_addr;
+}
+
+/*
+ * Check if sockaddr contains a non-zero address
+ */
+PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr)
+{
+ const pj_sockaddr *a = (const pj_sockaddr*)addr;
+
+ PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
+ a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP);
+
+ if (a->addr.sa_family == PJ_AF_INET6) {
+ pj_uint8_t zero[24];
+ pj_bzero(zero, sizeof(zero));
+ return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero,
+ sizeof(pj_in6_addr)) != 0;
+ } else
+ return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY;
+}
+
+/*
+ * Get port number
+ */
+PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr)
+{
+ const pj_sockaddr *a = (const pj_sockaddr*) addr;
+
+ PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
+ a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF);
+
+ return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ?
+ a->ipv6.sin6_port : a->ipv4.sin_port));
+}
+
+/*
+ * Get the length of the address part.
+ */
+PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr)
+{
+ const pj_sockaddr *a = (const pj_sockaddr*) addr;
+ PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
+ a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP);
+ return a->addr.sa_family == PJ_AF_INET6 ?
+ sizeof(pj_in6_addr) : sizeof(pj_in_addr);
+}
+
+/*
+ * Set port number of pj_sockaddr_in
+ */
+PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,
+ pj_uint16_t hostport)
+{
+ addr->sin_port = pj_htons(hostport);
+}
+
+/*
+ * Set port number of pj_sockaddr
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr,
+ pj_uint16_t hostport)
+{
+ int af = addr->addr.sa_family;
+
+ PJ_ASSERT_ON_FAIL(af == PJ_AF_INET || af == PJ_AF_INET6,
+ PJ_EINVAL);
+
+ if (af == PJ_AF_INET6)
+ addr->ipv6.sin6_port = pj_htons(hostport);
+ else
+ addr->ipv4.sin_port = pj_htons(hostport);
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get IPv4 address
+ */
+PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
+{
+ pj_in_addr in_addr;
+ in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
+ return in_addr;
+}
+
+/*
+ * Set IPv4 address
+ */
+PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
+ pj_uint32_t hostaddr)
+{
+ addr->sin_addr.s_addr = pj_htonl(hostaddr);
+}
+
+/* Resolve the IP address of local machine */
+PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
+{
+ unsigned count;
+ pj_addrinfo ai;
+ pj_status_t status;
+
+
+#ifdef _MSC_VER
+ /* Get rid of "uninitialized he variable" with MS compilers */
+ pj_bzero(&ai, sizeof(ai));
+#endif
+
+ addr->addr.sa_family = (pj_uint16_t)af;
+ PJ_SOCKADDR_RESET_LEN(addr);
+
+ /* Try with resolving local hostname first */
+ count = 1;
+ status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai);
+ if (status == PJ_SUCCESS) {
+ pj_memcpy(pj_sockaddr_get_addr(addr),
+ pj_sockaddr_get_addr(&ai.ai_addr),
+ pj_sockaddr_get_addr_len(&ai.ai_addr));
+ }
+
+
+ /* If we end up with 127.x.x.x, resolve the IP by getting the default
+ * interface to connect to some public host.
+ */
+ if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(addr) ||
+ (af==PJ_AF_INET && (pj_ntohl(addr->ipv4.sin_addr.s_addr) >> 24)==127))
+ {
+ status = pj_getdefaultipinterface(af, addr);
+ }
+
+ /* If failed, get the first available interface */
+ if (status != PJ_SUCCESS) {
+ pj_sockaddr itf[1];
+ unsigned count = PJ_ARRAY_SIZE(itf);
+
+ status = pj_enum_ip_interface(af, &count, itf);
+ if (status == PJ_SUCCESS) {
+ itf[0].addr.sa_family = (pj_uint16_t)af;
+ pj_memcpy(pj_sockaddr_get_addr(addr),
+ pj_sockaddr_get_addr(&itf[0]),
+ pj_sockaddr_get_addr_len(&itf[0]));
+ }
+ }
+
+ /* If else fails, returns loopback interface as the last resort */
+ if (status != PJ_SUCCESS) {
+ if (af==PJ_AF_INET) {
+ addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
+ } else {
+ pj_in6_addr *s6_addr;
+
+ s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
+ pj_bzero(s6_addr, sizeof(pj_in6_addr));
+ s6_addr->s6_addr[15] = 1;
+ }
+ status = PJ_SUCCESS;
+ }
+
+ return status;
+}
+
+/* Get the default IP interface */
+PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
+{
+ pj_sock_t fd;
+ pj_str_t cp;
+ pj_sockaddr a;
+ int len;
+ pj_uint8_t zero[64];
+ pj_status_t status;
+
+ addr->addr.sa_family = (pj_uint16_t)af;
+
+ status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ if (af == PJ_AF_INET) {
+ cp = pj_str("1.1.1.1");
+ } else {
+ cp = pj_str("1::1");
+ }
+ status = pj_sockaddr_init(af, &a, &cp, 53);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(fd);
+ return status;
+ }
+
+ status = pj_sock_connect(fd, &a, sizeof(a));
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(fd);
+ return status;
+ }
+
+ len = sizeof(a);
+ status = pj_sock_getsockname(fd, &a, &len);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(fd);
+ return status;
+ }
+
+ pj_sock_close(fd);
+
+ /* Check that the address returned is not zero */
+ pj_bzero(zero, sizeof(zero));
+ if (pj_memcmp(pj_sockaddr_get_addr(&a), zero,
+ pj_sockaddr_get_addr_len(&a))==0)
+ {
+ return PJ_ENOTFOUND;
+ }
+
+ pj_memcpy(pj_sockaddr_get_addr(addr),
+ pj_sockaddr_get_addr(&a),
+ pj_sockaddr_get_addr_len(&a));
+
+ /* Success */
+ return PJ_SUCCESS;
+}
+
+
+/* Only need to implement these in DLL build */
+#if defined(PJ_DLL)
PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void)
{
@@ -148,3 +558,5 @@ PJ_DEF(int) pj_MSG_DONTROUTE(void)
return PJ_MSG_DONTROUTE;
}
+#endif /* PJ_DLL */
+
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
index 67eea1a0..90044a35 100644
--- a/pjlib/src/pj/sock_symbian.cpp
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -442,85 +442,6 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
}
/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
- pj_in_addr addr;
-
- pj_inet_aton(cp, &addr);
- return addr;
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
-{
- pj_str_t str = pj_str((char*)cp);
- return pj_inet_addr(&str);
-}
-
-/*
- * Set the IP address of an IP socket address from string address,
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
- const pj_str_t *str_addr)
-{
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
- (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- addr->sin_family = PJ_AF_INET;
- pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero));
-
- if (str_addr && str_addr->slen) {
- addr->sin_addr = pj_inet_addr(str_addr);
- if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
- pj_hostent he;
- pj_status_t rc;
-
- rc = pj_gethostbyname(str_addr, &he);
- if (rc == 0) {
- addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- } else {
- addr->sin_addr.s_addr = PJ_INADDR_NONE;
- return rc;
- }
- }
-
- } else {
- addr->sin_addr.s_addr = 0;
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or
- * may be a hostname. If hostname is specified, then the function will
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
- const pj_str_t *str_addr,
- pj_uint16_t port)
-{
- PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- addr->sin_family = PJ_AF_INET;
- pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero));
- pj_sockaddr_in_set_port(addr, port);
- return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
* Get hostname.
*/
PJ_DEF(const pj_str_t*) pj_gethostname(void)
@@ -531,7 +452,7 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void)
PJ_CHECK_STACK();
if (hostname.ptr == NULL) {
- RHostResolver & resv = PjSymbianOS::Instance()->GetResolver();
+ RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(PJ_AF_INET);
TRequestStatus reqStatus;
THostName tmpName;
@@ -546,19 +467,6 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void)
}
/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
- pj_sockaddr_in addr;
- const pj_str_t *hostname = pj_gethostname();
-
- pj_sockaddr_in_set_str_addr(&addr, hostname);
- return addr.sin_addr;
-}
-
-
-/*
* Create new socket/endpoint for communication and returns a descriptor.
*/
PJ_DEF(pj_status_t) pj_sock_socket(int af,
@@ -596,7 +504,7 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af,
/* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */
- CPjSocket *pjSock = new CPjSocket(rSock);
+ CPjSocket *pjSock = new CPjSocket(af, rSock);
*p_sock = (pj_sock_t)pjSock;
return PJ_SUCCESS;
@@ -610,16 +518,19 @@ PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
const pj_sockaddr_t *addr,
int len)
{
+ pj_status_t status;
TInt rc;
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
- PJ_ASSERT_RETURN(addr && len == sizeof(pj_sockaddr_in), PJ_EINVAL);
+ PJ_ASSERT_RETURN(addr && len >= sizeof(pj_sockaddr_in), PJ_EINVAL);
- // Convert PJLIB's pj_sockaddr_in into Symbian's TInetAddr
+ // Convert PJLIB's pj_sockaddr into Symbian's TInetAddr
TInetAddr inetAddr;
- PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr);
+ status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, len, inetAddr);
+ if (status != PJ_SUCCESS)
+ return status;
// Get the RSocket instance
RSocket &rSock = ((CPjSocket*)sock)->Socket();
@@ -689,10 +600,7 @@ PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
TInetAddr inetAddr;
rSock.RemoteName(inetAddr);
- PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr);
- *namelen = sizeof(pj_sockaddr_in);
-
- return PJ_SUCCESS;
+ return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
}
/*
@@ -713,10 +621,7 @@ PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
TInetAddr inetAddr;
rSock.LocalName(inetAddr);
- PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr);
- *namelen = sizeof(pj_sockaddr_in);
-
- return PJ_SUCCESS;
+ return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen);
}
/*
@@ -761,6 +666,8 @@ PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
const pj_sockaddr_t *to,
int tolen)
{
+ pj_status_t status;
+
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL);
@@ -768,12 +675,12 @@ PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
RSocket &rSock = pjSock->Socket();
// Only supports AF_INET for now
- PJ_ASSERT_RETURN(tolen==sizeof(pj_sockaddr_in) &&
- ((pj_sockaddr*)to)->addr.sa_family == PJ_AF_INET,
- PJ_EINVAL);
+ PJ_ASSERT_RETURN(tolen >= sizeof(pj_sockaddr_in), PJ_EINVAL);
TInetAddr inetAddr;
- PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)to, inetAddr);
+ status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)to, tolen, inetAddr);
+ if (status != PJ_SUCCESS)
+ return status;
TPtrC8 data((const TUint8*)buf, (TInt)*len);
TRequestStatus reqStatus;
@@ -876,10 +783,11 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
*len = data.Length();
if (from && fromlen) {
- PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from);
- *fromlen = sizeof(pj_sockaddr_in);
+ return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from,
+ fromlen);
+ } else {
+ return PJ_SUCCESS;
}
- return PJ_SUCCESS;
}
}
@@ -894,9 +802,7 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
if (reqStatus == KErrNone) {
//*len = (TInt)recvLen.Length();
*len = data.Length();
- *fromlen = sizeof(pj_sockaddr_in);
- PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from);
- return PJ_SUCCESS;
+ return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen);
} else {
*len = -1;
*fromlen = -1;
@@ -947,6 +853,8 @@ PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
const pj_sockaddr_t *addr,
int namelen)
{
+ pj_status_t status;
+
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL);
@@ -959,7 +867,9 @@ PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
TInetAddr inetAddr;
TRequestStatus reqStatus;
- PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr);
+ status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, namelen, inetAddr);
+ if (status != PJ_SUCCESS)
+ return status;
rSock.Connect(inetAddr, reqStatus);
User::WaitForRequest(reqStatus);
@@ -1059,7 +969,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
}
// Create PJ socket
- CPjSocket *newPjSock = new CPjSocket(newSock);
+ CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), newSock);
newPjSock->SetConnected(true);
*newsock = (pj_sock_t) newPjSock;