Index: /pjproject/trunk/pjlib-util/src/pjlib-util/dns_dump.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/dns_dump.c	(revision 1612)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/dns_dump.c	(revision 1613)
@@ -121,6 +121,6 @@
 	char addr[PJ_INET6_ADDRSTRLEN];
 	PJ_LOG(3,(THIS_FILE, "    IPv6 address: %s",
-		  pj_inet_ntop(pj_AF_INET6(), &rr->rdata.aaaa.ip_addr,
-			       addr, sizeof(addr))));
+		  pj_inet_ntop2(pj_AF_INET6(), &rr->rdata.aaaa.ip_addr,
+			        addr, sizeof(addr))));
     }
 }
Index: /pjproject/trunk/pjlib/include/pj/sock.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/sock.h	(revision 1612)
+++ /pjproject/trunk/pjlib/include/pj/sock.h	(revision 1613)
@@ -596,5 +596,6 @@
  * This function converts a numeric address into a text string suitable
  * for presentation. It supports both IPv4 and IPv6 address
- * conversion.
+ * conversion. 
+ * @see pj_sockaddr_print()
  *
  * @param af	Specify the family of the address. This can be PJ_AF_INET
@@ -616,4 +617,5 @@
 /**
  * Converts numeric address into its text string representation.
+ * @see pj_sockaddr_print()
  *
  * @param af	Specify the family of the address. This can be PJ_AF_INET
@@ -633,4 +635,19 @@
 			     char *dst, int size);
 
+/**
+ * Print socket address.
+ *
+ * @param addr	The socket address.
+ * @param buf	Text buffer.
+ * @param size	Size of buffer.
+ * @param flags	Bitmask combination of these value:
+ *		  - 1: port number is included.
+ *		  - 2: square bracket is included for IPv6 address.
+ *
+ * @return	The address string.
+ */
+PJ_DECL(char*) pj_sockaddr_print(const pj_sockaddr_t *addr,
+				 char *buf, int size,
+				 unsigned flags);
 
 /**
@@ -703,4 +720,16 @@
 
 /**
+ * Compare two socket addresses.
+ *
+ * @param addr1	    First address.
+ * @param addr2	    Second address.
+ *
+ * @return	    Zero on equal, -1 if addr1 is less than addr2,
+ *		    and +1 if addr1 is more than addr2.
+ */
+PJ_DECL(int) pj_sockaddr_cmp(const pj_sockaddr_t *addr1,
+			     const pj_sockaddr_t *addr2);
+
+/**
  * Get pointer to the address part of a socket address.
  * 
@@ -743,4 +772,12 @@
 PJ_DECL(unsigned) pj_sockaddr_get_len(const pj_sockaddr_t *addr);
 
+/** 
+ * Copy only the address part (sin_addr/sin6_addr) of a socket address.
+ *
+ * @param dst	    Destination socket address.
+ * @param src	    Source socket address.
+ */
+PJ_DECL(void) pj_sockaddr_copy_addr(pj_sockaddr *dst,
+				    const pj_sockaddr *src);
 /**
  * Get the IP address of an IPv4 socket address.
Index: /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c	(revision 1612)
+++ /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c	(revision 1613)
@@ -274,7 +274,4 @@
     PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && ifs, PJ_EINVAL);
 
-    PJ_UNUSED_ARG(&get_addr);
-    PJ_UNUSED_ARG(&get_os_errmsg);
-
     pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
 
Index: /pjproject/trunk/pjlib/src/pj/sock_common.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/sock_common.c	(revision 1612)
+++ /pjproject/trunk/pjlib/src/pj/sock_common.c	(revision 1613)
@@ -60,4 +60,46 @@
 
 /*
+ * Print socket address.
+ */
+PJ_DEF(char*) pj_sockaddr_print( const pj_sockaddr_t *addr,
+				 char *buf, int size,
+				 unsigned flags)
+{
+    enum {
+	WITH_PORT = 1,
+	WITH_BRACKETS = 2
+    };
+
+    char txt[PJ_INET6_ADDRSTRLEN];
+    char port[32];
+    const pj_addr_hdr *h = (const pj_addr_hdr*)addr;
+    char *bquote, *equote;
+    pj_status_t status;
+
+    status = pj_inet_ntop(h->sa_family, pj_sockaddr_get_addr(addr),
+			  txt, sizeof(txt));
+    if (status != PJ_SUCCESS)
+	return "";
+
+    if (h->sa_family != PJ_AF_INET6 || (flags & WITH_BRACKETS)==0) {
+	bquote = ""; equote = "";
+    } else {
+	bquote = "["; equote = "]";
+    }
+
+    if (flags & WITH_PORT) {
+	pj_ansi_snprintf(port, sizeof(port), ":%d",
+			 pj_sockaddr_get_port(addr));
+    } else {
+	port[0] = '\0';
+    }
+
+    pj_ansi_snprintf(buf, size, "%s%s%s%s",
+		     bquote, txt, equote, port);
+
+    return buf;
+}
+
+/*
  * 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
@@ -185,4 +227,45 @@
 
 /*
+ * Compare two socket addresses.
+ */
+PJ_DEF(int) pj_sockaddr_cmp( const pj_sockaddr_t *addr1,
+			     const pj_sockaddr_t *addr2)
+{
+    const pj_sockaddr *a1 = (const pj_sockaddr*) addr1;
+    const pj_sockaddr *a2 = (const pj_sockaddr*) addr2;
+    int port1, port2;
+    int result;
+
+    /* Compare address family */
+    if (a1->addr.sa_family < a2->addr.sa_family)
+	return -1;
+    else if (a1->addr.sa_family > a2->addr.sa_family)
+	return 1;
+
+    /* Compare addresses */
+    result = pj_memcmp(pj_sockaddr_get_addr(a1),
+		       pj_sockaddr_get_addr(a2),
+		       pj_sockaddr_get_addr_len(a1));
+    if (result != 0)
+	return result;
+
+    /* Compare port number */
+    port1 = pj_sockaddr_get_port(a1);
+    port2 = pj_sockaddr_get_port(a2);
+
+    if (port1 < port2)
+	return -1;
+    else if (port1 > port2)
+	return 1;
+
+    /* TODO:
+     *	Do we need to compare flow label and scope id in IPv6? 
+     */
+    
+    /* Looks equal */
+    return 0;
+}
+
+/*
  * Get first IP address associated with the hostname.
  */
@@ -278,4 +361,15 @@
 
 /*
+ * Copy only the address part (sin_addr/sin6_addr) of a socket address.
+ */
+PJ_DEF(void) pj_sockaddr_copy_addr( pj_sockaddr *dst,
+				    const pj_sockaddr *src)
+{
+    pj_memcpy(pj_sockaddr_get_addr(dst),
+	      pj_sockaddr_get_addr(src),
+	      pj_sockaddr_get_addr_len(src));
+}
+
+/*
  * Set port number of pj_sockaddr_in
  */
