More ticket #415: more IPv6 and some reorganization of the source codes

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1601 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h
index b066bc9..cad8273 100644
--- a/pjlib/include/pj/addr_resolv.h
+++ b/pjlib/include/pj/addr_resolv.h
@@ -85,9 +85,14 @@
 
 /**
  * This function fills the structure of type pj_hostent for a given host name.
+ * For host resolution function that also works with IPv6, please see
+ * #pj_getaddrinfo().
  *
- * @param name	    Host name, or IPv4 or IPv6 address in standard dot notation.
- * @param he	    The pj_hostent structure to be filled.
+ * @param name	    Host name, or IPv4 address in standard dot notation.
+ * @param he	    The pj_hostent structure to be filled. Note that
+ *		    the pointers in this structure points to temporary
+ *		    variables which value will be reset upon subsequent
+ *		    invocation.
  *
  * @return	    PJ_SUCCESS, or the appropriate error codes.
  */ 
@@ -97,24 +102,33 @@
 /**
  * Resolve the primary IP address of local host. 
  *
- * @param ip_addr   On successful resolution, this will be filled up with
- *		    the host IP address, in network byte order.
+ * @param af	    The desired address family to query. Valid values
+ *		    are pj_AF_INET() or pj_AF_INET6().
+ * @param addr      On successful resolution, the address family and address
+ *		    part of this socket address will be filled up with the host
+ *		    IP address, in network byte order. Other parts of the socket
+ *		    address are untouched.
  *
  * @return	    PJ_SUCCESS on success, or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_gethostip(pj_in_addr *ip_addr);
+PJ_DECL(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr);
 
 
 /**
  * Get the IP address of the default interface. Default interface is the
  * interface of the default route.
  *
- * @param ip_addr   On successful resolution, this will be filled up with
- *		    the IP address, in network byte order.
+ * @param af	    The desired address family to query. Valid values
+ *		    are pj_AF_INET() or pj_AF_INET6().
+ * @param addr      On successful resolution, the address family and address
+ *		    part of this socket address will be filled up with the host
+ *		    IP address, in network byte order. Other parts of the socket
+ *		    address are untouched.
  *
  * @return	    PJ_SUCCESS on success, or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_getdefaultipinterface(pj_in_addr *ip_addr);
+PJ_DECL(pj_status_t) pj_getdefaultipinterface(int af,
+					      pj_sockaddr *addr);
 
 
 /**
@@ -123,17 +137,20 @@
  * to be used in creating a socket with which to address the specified 
  * service.
  *
+ * @param af	    The desired address family to query. Valid values
+ *		    are pj_AF_INET(), pj_AF_INET6(), or pj_AF_UNSPEC().
  * @param name	    Descriptive name or an address string, such as host
  *		    name.
- * @param af	    The desired address family to query.
  * @param count	    On input, it specifies the number of elements in
  *		    \a ai array. On output, this will be set with the
  *		    number of address informations found for the
  *		    specified name.
+ * @param ai	    Array of address info to be filled with the information
+ *		    about the host.
  *
  * @return	    PJ_SUCCESS on success, or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af,
+PJ_DECL(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *name,
 				    unsigned *count, pj_addrinfo ai[]);
 
 
diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h
index f44a623..989cda5 100644
--- a/pjlib/include/pj/compat/socket.h
+++ b/pjlib/include/pj/compat/socket.h
@@ -185,6 +185,28 @@
     typedef int socklen_t;
 #endif
 
+/* Regarding sin_len member of sockaddr_in:
+ *  BSD systems (including MacOS X requires that the sin_len member of 
+ *  sockaddr_in be set to sizeof(sockaddr_in), while other systems (Windows
+ *  and Linux included) do not.
+ *
+ *  To maintain compatibility between systems, PJLIB will automatically
+ *  set this field before invoking native OS socket API, and it will
+ *  always reset the field to zero before returning pj_sockaddr_in to
+ *  application (such as in pj_getsockname() and pj_recvfrom()).
+ *
+ *  Application MUST always set this field to zero.
+ *
+ *  This way we can avoid hard to find problem such as when the socket 
+ *  address is used as hash table key.
+ */
+#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
+#   define PJ_SOCKADDR_SET_LEN(addr,len) (((pj_addr_hdr*)(addr))->sa_zero_len=(len))
+#   define PJ_SOCKADDR_RESET_LEN(addr)   (((pj_addr_hdr*)(addr))->sa_zero_len=0)
+#else
+#   define PJ_SOCKADDR_SET_LEN(addr,len) 
+#   define PJ_SOCKADDR_RESET_LEN(addr)
+#endif
 
 #endif	/* __PJ_COMPAT_SOCKET_H__ */
 
diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h
index 507bd7b..b838f06 100644
--- a/pjlib/include/pj/errno.h
+++ b/pjlib/include/pj/errno.h
@@ -314,6 +314,11 @@
  * IPv6 is not supported
  */
 #define PJ_EIPV6NOTSUP	    (PJ_ERRNO_START_STATUS + 21)/* 70021 */
+/**
+ * @hideinitializer
+ * Unsupported address family
+ */
+#define PJ_EAFNOTSUP	    (PJ_ERRNO_START_STATUS + 22)/* 70022 */
 
 /** @} */   /* pj_errnum */
 
diff --git a/pjlib/include/pj/ip_helper.h b/pjlib/include/pj/ip_helper.h
index 9515d97..266a785 100644
--- a/pjlib/include/pj/ip_helper.h
+++ b/pjlib/include/pj/ip_helper.h
@@ -53,16 +53,24 @@
 
 
 /**
- * Enumerate the local IP interface currently active in the host.
+ * Enumerate the local IP interfaces currently active in the host.
  *
+ * @param af	    Family of the address to be retrieved. Application
+ *		    may specify pj_AF_UNSPEC() to retrieve all addresses,
+ *		    or pj_AF_INET() or pj_AF_INET6() to retrieve interfaces
+ *		    with specific address family.
  * @param count	    On input, specify the number of entries. On output,
  *		    it will be filled with the actual number of entries.
- * @param ifs	    Array of IP addresses.
+ * @param ifs	    Array of socket addresses, which address part will
+ *		    be filled with the interface address. The address
+ *		    family part will be initialized with the address
+ *		    family of the IP address.
  *
  * @return	    PJ_SUCCESS on success, or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_enum_ip_interface(unsigned *count,
-					  pj_in_addr ifs[]);
+PJ_DECL(pj_status_t) pj_enum_ip_interface(int af,
+					  unsigned *count,
+					  pj_sockaddr ifs[]);
 
 
 /**
diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h
index f640df2..a5c10df 100644
--- a/pjlib/include/pj/os.h
+++ b/pjlib/include/pj/os.h
@@ -334,6 +334,13 @@
      */
     void 	*rhostresolver;
      
+    /**
+     * Optional RHostResolver for IPv6 instance to be used by PJLIB. 
+     * If this value is NULL, a new RHostResolver instance will be created
+     * when pj_init() is called.
+     */
+    void 	*rhostresolver6;
+     
 } pj_symbianos_params;
 
 /**
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index d90c91e..1d3b035 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -87,18 +87,36 @@
  * global variables from a DLL.
  */
 
-/** Get #PJ_AF_UNSPEC value */
-PJ_DECL(pj_uint16_t) pj_AF_UNSPEC(void);
-/** Get #PJ_AF_UNIX value. */
-PJ_DECL(pj_uint16_t) pj_AF_UNIX(void);
-/** Get #PJ_AF_INET value. */
-PJ_DECL(pj_uint16_t) pj_AF_INET(void);
-/** Get #PJ_AF_INET6 value. */
-PJ_DECL(pj_uint16_t) pj_AF_INET6(void);
-/** Get #PJ_AF_PACKET value. */
-PJ_DECL(pj_uint16_t) pj_AF_PACKET(void);
-/** Get #PJ_AF_IRDA value. */
-PJ_DECL(pj_uint16_t) pj_AF_IRDA(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_AF_UNSPEC value */
+    PJ_DECL(pj_uint16_t) pj_AF_UNSPEC(void);
+    /** Get #PJ_AF_UNIX value. */
+    PJ_DECL(pj_uint16_t) pj_AF_UNIX(void);
+    /** Get #PJ_AF_INET value. */
+    PJ_DECL(pj_uint16_t) pj_AF_INET(void);
+    /** Get #PJ_AF_INET6 value. */
+    PJ_DECL(pj_uint16_t) pj_AF_INET6(void);
+    /** Get #PJ_AF_PACKET value. */
+    PJ_DECL(pj_uint16_t) pj_AF_PACKET(void);
+    /** Get #PJ_AF_IRDA value. */
+    PJ_DECL(pj_uint16_t) pj_AF_IRDA(void);
+#else
+    /* When pjlib is not built as DLL, these accessor functions are
+     * simply a macro to get their constants
+     */
+    /** Get #PJ_AF_UNSPEC value */
+#   define pj_AF_UNSPEC()   PJ_AF_UNSPEC
+    /** Get #PJ_AF_UNIX value. */
+#   define pj_AF_UNIX()	    PJ_AF_UNIX
+    /** Get #PJ_AF_INET value. */
+#   define pj_AF_INET()	    PJ_AF_INET
+    /** Get #PJ_AF_INET6 value. */
+#   define pj_AF_INET6()    PJ_AF_INET6
+    /** Get #PJ_AF_PACKET value. */
+#   define pj_AF_PACKET()   PJ_AF_PACKET
+    /** Get #PJ_AF_IRDA value. */
+#   define pj_AF_IRDA()	    PJ_AF_IRDA
+#endif
 
 
 /**
@@ -127,14 +145,25 @@
  * because Symbian doesn't allow exporting global variables from a DLL.
  */
 
-/** Get #PJ_SOCK_STREAM constant */
-PJ_DECL(int) pj_SOCK_STREAM(void);
-/** Get #PJ_SOCK_DGRAM constant */
-PJ_DECL(int) pj_SOCK_DGRAM(void);
-/** Get #PJ_SOCK_RAW constant */
-PJ_DECL(int) pj_SOCK_RAW(void);
-/** Get #PJ_SOCK_RDM constant */
-PJ_DECL(int) pj_SOCK_RDM(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_SOCK_STREAM constant */
+    PJ_DECL(int) pj_SOCK_STREAM(void);
+    /** Get #PJ_SOCK_DGRAM constant */
+    PJ_DECL(int) pj_SOCK_DGRAM(void);
+    /** Get #PJ_SOCK_RAW constant */
+    PJ_DECL(int) pj_SOCK_RAW(void);
+    /** Get #PJ_SOCK_RDM constant */
+    PJ_DECL(int) pj_SOCK_RDM(void);
+#else
+    /** Get #PJ_SOCK_STREAM constant */
+#   define pj_SOCK_STREAM() PJ_SOCK_STREAM
+    /** Get #PJ_SOCK_DGRAM constant */
+#   define pj_SOCK_DGRAM()  PJ_SOCK_DGRAM
+    /** Get #PJ_SOCK_RAW constant */
+#   define pj_SOCK_RAW()    PJ_SOCK_RAW
+    /** Get #PJ_SOCK_RDM constant */
+#   define pj_SOCK_RDM()    PJ_SOCK_RDM
+#endif
 
 
 /**
@@ -158,16 +187,29 @@
  * because Symbian doesn't allow exporting global variables from a DLL.
  */
 
-/** Get #PJ_SOL_SOCKET constant */
-PJ_DECL(pj_uint16_t) pj_SOL_SOCKET(void);
-/** Get #PJ_SOL_IP constant */
-PJ_DECL(pj_uint16_t) pj_SOL_IP(void);
-/** Get #PJ_SOL_TCP constant */
-PJ_DECL(pj_uint16_t) pj_SOL_TCP(void);
-/** Get #PJ_SOL_UDP constant */
-PJ_DECL(pj_uint16_t) pj_SOL_UDP(void);
-/** Get #PJ_SOL_IPV6 constant */
-PJ_DECL(pj_uint16_t) pj_SOL_IPV6(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_SOL_SOCKET constant */
+    PJ_DECL(pj_uint16_t) pj_SOL_SOCKET(void);
+    /** Get #PJ_SOL_IP constant */
+    PJ_DECL(pj_uint16_t) pj_SOL_IP(void);
+    /** Get #PJ_SOL_TCP constant */
+    PJ_DECL(pj_uint16_t) pj_SOL_TCP(void);
+    /** Get #PJ_SOL_UDP constant */
+    PJ_DECL(pj_uint16_t) pj_SOL_UDP(void);
+    /** Get #PJ_SOL_IPV6 constant */
+    PJ_DECL(pj_uint16_t) pj_SOL_IPV6(void);
+#else
+    /** Get #PJ_SOL_SOCKET constant */
+#   define pj_SOL_SOCKET()  PJ_SOL_SOCKET
+    /** Get #PJ_SOL_IP constant */
+#   define pj_SOL_IP()	    PJ_SOL_IP
+    /** Get #PJ_SOL_TCP constant */
+#   define pj_SOL_TCP()	    PJ_SOL_TCP
+    /** Get #PJ_SOL_UDP constant */
+#   define pj_SOL_UDP()	    PJ_SOL_UDP
+    /** Get #PJ_SOL_IPV6 constant */
+#   define pj_SOL_IPV6()    PJ_SOL_IPV6
+#endif
 
 
 /* IP_TOS 
@@ -179,9 +221,6 @@
 /** IP_TOS optname in setsockopt(). @see pj_IP_TOS() */
 extern const pj_uint16_t PJ_IP_TOS;
 
-/** Get #PJ_IP_TOS constant */
-PJ_DECL(int) pj_IP_TOS(void);
-
 /*
  * IP TOS related constats.
  *
@@ -203,17 +242,37 @@
 extern const pj_uint16_t PJ_IPTOS_MINCOST;
 
 
-/** Get #PJ_IPTOS_LOWDELAY constant */
-PJ_DECL(int) pj_IPTOS_LOWDELAY(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_IP_TOS constant */
+    PJ_DECL(int) pj_IP_TOS(void);
 
-/** Get #PJ_IPTOS_THROUGHPUT constant */
-PJ_DECL(int) pj_IPTOS_THROUGHPUT(void);
+    /** Get #PJ_IPTOS_LOWDELAY constant */
+    PJ_DECL(int) pj_IPTOS_LOWDELAY(void);
 
-/** Get #PJ_IPTOS_RELIABILITY constant */
-PJ_DECL(int) pj_IPTOS_RELIABILITY(void);
+    /** Get #PJ_IPTOS_THROUGHPUT constant */
+    PJ_DECL(int) pj_IPTOS_THROUGHPUT(void);
 
-/** Get #PJ_IPTOS_MINCOST constant */
-PJ_DECL(int) pj_IPTOS_MINCOST(void);
+    /** Get #PJ_IPTOS_RELIABILITY constant */
+    PJ_DECL(int) pj_IPTOS_RELIABILITY(void);
+
+    /** Get #PJ_IPTOS_MINCOST constant */
+    PJ_DECL(int) pj_IPTOS_MINCOST(void);
+#else
+    /** Get #PJ_IP_TOS constant */
+#   define pj_IP_TOS()		PJ_IP_TOS
+
+    /** Get #PJ_IPTOS_LOWDELAY constant */
+#   define pj_IPTOS_LOWDELAY()	PJ_IP_TOS_LOWDELAY
+
+    /** Get #PJ_IPTOS_THROUGHPUT constant */
+#   define pj_IPTOS_THROUGHPUT() PJ_IP_TOS_THROUGHPUT
+
+    /** Get #PJ_IPTOS_RELIABILITY constant */
+#   define pj_IPTOS_RELIABILITY() PJ_IP_TOS_RELIABILITY
+
+    /** Get #PJ_IPTOS_MINCOST constant */
+#   define pj_IPTOS_MINCOST()	PJ_IP_TOS_MINCOST
+#endif
 
 
 /**
@@ -231,14 +290,25 @@
 extern const pj_uint16_t PJ_SO_SNDBUF;
 
 
-/** Get #PJ_SO_TYPE constant */
-PJ_DECL(pj_uint16_t) pj_SO_TYPE(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_SO_TYPE constant */
+    PJ_DECL(pj_uint16_t) pj_SO_TYPE(void);
 
-/** Get #PJ_SO_RCVBUF constant */
-PJ_DECL(pj_uint16_t) pj_SO_RCVBUF(void);
+    /** Get #PJ_SO_RCVBUF constant */
+    PJ_DECL(pj_uint16_t) pj_SO_RCVBUF(void);
 
-/** Get #PJ_SO_SNDBUF constant */
-PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void);
+    /** Get #PJ_SO_SNDBUF constant */
+    PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void);
+#else
+    /** Get #PJ_SO_TYPE constant */
+#   define pj_SO_TYPE()	    PJ_SO_TYPE
+
+    /** Get #PJ_SO_RCVBUF constant */
+#   define pj_SO_RCVBUF()   PJ_SO_RCVBUF
+
+    /** Get #PJ_SO_SNDBUF constant */
+#   define pj_SO_SNDBUF()   PJ_SO_SNDBUF
+#endif
 
 
 /*
@@ -255,14 +325,25 @@
 extern const int PJ_MSG_DONTROUTE;
 
 
-/** Get #PJ_MSG_OOB constant */
-PJ_DECL(int) pj_MSG_OOB(void);
+#if defined(PJ_DLL)
+    /** Get #PJ_MSG_OOB constant */
+    PJ_DECL(int) pj_MSG_OOB(void);
 
-/** Get #PJ_MSG_PEEK constant */
-PJ_DECL(int) pj_MSG_PEEK(void);
+    /** Get #PJ_MSG_PEEK constant */
+    PJ_DECL(int) pj_MSG_PEEK(void);
 
-/** Get #PJ_MSG_DONTROUTE constant */
-PJ_DECL(int) pj_MSG_DONTROUTE(void);
+    /** Get #PJ_MSG_DONTROUTE constant */
+    PJ_DECL(int) pj_MSG_DONTROUTE(void);
+#else
+    /** Get #PJ_MSG_OOB constant */
+#   define pj_MSG_OOB()		PJ_MSG_OOB
+
+    /** Get #PJ_MSG_PEEK constant */
+#   define pj_MSG_PEEK()	PJ_MSG_PEEK
+
+    /** Get #PJ_MSG_DONTROUTE constant */
+#   define pj_MSG_DONTROUTE()	PJ_MSG_DONTROUTE
+#endif
 
 
 /**
@@ -306,6 +387,7 @@
  */
 #define PJ_INVALID_SOCKET   (-1)
 
+/* Must undefine s_addr because of pj_in_addr below */
 #undef s_addr
 
 /**
@@ -362,7 +444,12 @@
 
     /* While these are used for proper alignment */
     pj_uint32_t	u6_addr32[4];
-#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
+
+    /* Do not use this with Winsock2, as this will align pj_sockaddr_in6
+     * to 64-bit boundary and Winsock2 doesn't like it!
+     */
+#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 && \
+    (!defined(PJ_WIN32) || PJ_WIN32==0)
     pj_int64_t	u6_addr64[2];
 #endif
 
@@ -555,77 +642,13 @@
 PJ_DECL(pj_in_addr) pj_inet_addr2(const char *cp);
 
 /**
- * Get the transport layer port number of an Internet socket address.
- * The port is returned in host byte order.
- *
- * @param addr	    The IP socket address.
- * @return	    Port number, in host byte order.
- */
-PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
-{
-    return pj_ntohs(addr->sin_port);
-}
-
-/**
- * Set the port number of an Internet socket address.
- *
- * @param addr	    The IP socket address.
- * @param hostport  The port number, in host byte order.
- */
-PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 
-					pj_uint16_t hostport)
-{
-    addr->sin_port = pj_htons(hostport);
-}
-
-/**
- * Get the IP address of an Internet socket address.
- * The address is returned as 32bit value in host byte order.
- *
- * @param addr	    The IP socket address.
- * @return	    32bit address, in host byte order.
- */
-PJ_INLINE(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 the IP address of an Internet socket address.
- *
- * @param addr	    The IP socket address.
- * @param hostaddr  The host address, in host byte order.
- */
-PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
-					pj_uint32_t hostaddr)
-{
-    addr->sin_addr.s_addr = pj_htonl(hostaddr);
-}
-
-/**
- * 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.
- *
- * @param addr	    The IP socket address to be set.
- * @param cp	    The address string, which can be in a standard 
- *		    dotted numbers or a hostname to be resolved.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
-					          const pj_str_t *cp);
-
-/**
- * Set the IP address and port of an IP socket address.
+ * Initialize IPv4 socket address based on the address and port info.
  * 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.
  *
+ * @see pj_sockaddr_init()
+ *
  * @param addr	    The IP socket address to be set.
  * @param cp	    The address string, which can be in a standard 
  *		    dotted numbers or a hostname to be resolved.
@@ -637,6 +660,149 @@
 				          const pj_str_t *cp,
 					  pj_uint16_t port);
 
+/**
+ * Initialize IP socket address based on the address and port info.
+ * 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.
+ *
+ * @see pj_sockaddr_in_init()
+ *
+ * @param af	    Internet address family.
+ * @param addr	    The IP socket address to be set.
+ * @param cp	    The address string, which can be in a standard 
+ *		    dotted numbers or a hostname to be resolved.
+ * @param port	    The port number, in host byte order.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_init(int af, 
+				      pj_sockaddr *addr,
+				      const pj_str_t *cp,
+				      pj_uint16_t port);
+
+/**
+ * Get pointer to the address part of a socket address.
+ * 
+ * @param addr	    Socket address.
+ *
+ * @return	    Pointer to address part (sin_addr or sin6_addr,
+ *		    depending on address family)
+ */
+PJ_DECL(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr);
+
+/**
+ * Check that a socket address contains a non-zero address part.
+ *
+ * @param addr	    Socket address.
+ *
+ * @return	    Non-zero if address is set to non-zero.
+ */
+PJ_DECL(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr);
+
+/**
+ * Get the address part length of a socket address, based on its address
+ * family. For PJ_AF_INET, the length will be sizeof(pj_in_addr), and
+ * for PJ_AF_INET6, the length will be sizeof(pj_in6_addr).
+ * 
+ * @param addr	    Socket address.
+ *
+ * @return	    Port number, in host byte order.
+ */
+PJ_DECL(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr);
+
+/**
+ * Get the IP address of an IPv4 socket address.
+ * The address is returned as 32bit value in host byte order.
+ *
+ * @param addr	    The IP socket address.
+ * @return	    32bit address, in host byte order.
+ */
+PJ_DECL(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr);
+
+/**
+ * Set the IP address of an IPv4 socket address.
+ *
+ * @param addr	    The IP socket address.
+ * @param hostaddr  The host address, in host byte order.
+ */
+PJ_DECL(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
+				      pj_uint32_t hostaddr);
+
+/**
+ * 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.
+ *
+ * @see pj_sockaddr_set_str_addr()
+ *
+ * @param addr	    The IP socket address to be set.
+ * @param cp	    The address string, which can be in a standard 
+ *		    dotted numbers or a hostname to be resolved.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+					          const pj_str_t *cp);
+
+/**
+ * Set the IP address of an IPv4 or IPv6 socket address from string address,
+ * with resolving the host if necessary. The string address may be in a
+ * standard IPv6 or IPv6 address or may be a hostname. If hostname
+ * is specified, then the function will resolve the host into the IP
+ * address according to the address family.
+ *
+ * @param af	    Address family.
+ * @param addr	    The IP socket address to be set.
+ * @param cp	    The address string, which can be in a standard 
+ *		    IP numbers (IPv4 or IPv6) or a hostname to be resolved.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_set_str_addr(int af,
+					      pj_sockaddr *addr,
+					      const pj_str_t *cp);
+
+/**
+ * Get the port number of a socket address, in host byte order. 
+ * This function can be used for both IPv4 and IPv6 socket address.
+ * 
+ * @param addr	    Socket address.
+ *
+ * @return	    Port number, in host byte order.
+ */
+PJ_DECL(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr);
+
+/**
+ * Get the transport layer port number of an Internet socket address.
+ * The port is returned in host byte order.
+ *
+ * @param addr	    The IP socket address.
+ * @return	    Port number, in host byte order.
+ */
+PJ_DECL(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr);
+
+/**
+ * Set the port number of an Internet socket address.
+ *
+ * @param addr	    The socket address.
+ * @param hostport  The port number, in host byte order.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr, 
+					  pj_uint16_t hostport);
+
+/**
+ * Set the port number of an IPv4 socket address.
+ *
+ * @see pj_sockaddr_set_port()
+ *
+ * @param addr	    The IP socket address.
+ * @param hostport  The port number, in host byte order.
+ */
+PJ_DECL(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 
+				      pj_uint16_t hostport);
 
 /*****************************************************************************
  *
diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c
index a4599ef..aeb6195 100644
--- a/pjlib/src/pj/addr_resolv_sock.c
+++ b/pjlib/src/pj/addr_resolv_sock.c
@@ -55,96 +55,8 @@
     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_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 @@
 	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 @@
     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 496c1f8..d2bc636 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 @@
     resv.GetByName(data, nameEntry, reqStatus);
     User::WaitForRequest(reqStatus);
     
-    if (reqStatus != KErrNone)
-	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    // Iterate each result
+    i = 0;
+    while (reqStatus == KErrNone && i < *count) {
+    	
+	// Get the resolved TInetAddr
+	TInetAddr inetAddr(nameEntry().iAddr);
+	int addrlen;
 
-    // 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;
-    }
-
-    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;
-
-
-    /* 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);
-	    }
+	// 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);
     }
 
-    return status;
+    *count = i;
+    return PJ_SUCCESS;
 }
 
+/* Resolve IPv4/IPv6 address */
+PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
+				   unsigned *count, pj_addrinfo ai[]) 
+{
+    unsigned start;
+    pj_status_t status;
+    
+    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 (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;
+    	}
+    }
+    
+    *count = start;
+    
+    if (*count) {
+    	return PJ_SUCCESS;
+    } else {
+    	return status!=PJ_SUCCESS ? status : PJ_ENOTFOUND;
+    }
+}
 
diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 6de0c92..1b86d4c 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -71,7 +71,8 @@
     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 90848f5..d7aa9d6 100644
--- a/pjlib/src/pj/ioqueue_symbian.cpp
+++ b/pjlib/src/pj/ioqueue_symbian.cpp
@@ -232,6 +232,10 @@
     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 @@
 //
 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 @@
 //
 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 @@
 
 	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 @@
 					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_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 @@
     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 a928480..8a2ea78 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 @@
     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 @@
 }
 
 #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 @@
     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 @@
 	*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 @@
 /*
  * 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_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_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 0000000..3cd2ebf
--- /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 1a937d7..d5cc969 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 @@
 
 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 @@
     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 @@
     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 @@
     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,15 +215,73 @@
 	    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 f656cb6..c193fb5 100644
--- a/pjlib/src/pj/os_core_symbian.cpp
+++ b/pjlib/src/pj/os_core_symbian.cpp
@@ -154,7 +154,8 @@
 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 @@
     appSocketServ_ = (RSocketServ*) params->rsocketserv;
     appConnection_ = (RConnection*) params->rconnection;
     appHostResolver_ = (RHostResolver*) params->rhostresolver;
+    appHostResolver6_ = (RHostResolver*) params->rhostresolver6;
 }
 
 // Get PjSymbianOS instance
@@ -199,16 +201,29 @@
 	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 (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;
+    	}
+    	
 	isResolverInitialized_ = true;
     }
 
@@ -224,6 +239,7 @@
 {
     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 2b14ecd..f564075 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 @@
     };
 
     // 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 @@
     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 @@
     }
     
     // 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 @@
     //
 
     // 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 @@
 
     bool isResolverInitialized_;
     RHostResolver hostResolver_;
+    RHostResolver hostResolver6_;
 
     CConsoleBase* console_;
 
@@ -312,6 +360,7 @@
     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 156ded8..761c03b 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -123,15 +123,6 @@
 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 @@
 {
     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 @@
 
     *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 @@
 	    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 @@
 }
 
 /*
- * 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 @@
     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_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 @@
     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 @@
     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 @@
     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 @@
 
 #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 @@
 	
 #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 5b629fc..06aa941 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 @@
     return PJ_MSG_DONTROUTE;
 }
 
+#endif	/* PJ_DLL */
+
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
index 67eea1a..90044a3 100644
--- a/pjlib/src/pj/sock_symbian.cpp
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -442,85 +442,6 @@
 }
 
 /*
- * 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_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 @@
 }
 
 /*
- * 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 @@
 
 
     /* 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 @@
 				  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 @@
     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 @@
     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 @@
 				   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 @@
     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 @@
 	    *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 @@
     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 @@
 				     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 @@
     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 @@
     }
 
     // Create PJ socket
-    CPjSocket *newPjSock = new CPjSocket(newSock);
+    CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), newSock);
     newPjSock->SetConnected(true);
 
     *newsock = (pj_sock_t) newPjSock;