Index: pjproject/trunk/pjsip/include/pjsip/sip_transport.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 1601)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 1602)
@@ -134,4 +134,13 @@
 
 /**
+ * Get the socket address family of a given transport type.
+ *
+ * @param type	    Transport type.
+ *
+ * @return	    Transport type.
+ */
+PJ_DECL(int) pjsip_transport_type_get_af(pjsip_transport_type_e type);
+
+/**
  * Get transport flag from type.
  *
@@ -162,4 +171,13 @@
  */
 PJ_DECL(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e t);
+
+/**
+ * Get longer description for the specified transport type.
+ *
+ * @param t	    Transport type.
+ *
+ * @return	    Transport description.
+ */
+PJ_DECL(const char*) pjsip_transport_get_type_desc(pjsip_transport_type_e t);
 
 
@@ -308,5 +326,5 @@
 
 	/** The IP source address string (NULL terminated). */
-	char			 src_name[16];
+	char			 src_name[PJ_INET6_ADDRSTRLEN];
 
 	/** The IP source port number. */
@@ -507,5 +525,5 @@
 	pj_sockaddr	     dst_addr;	    /**< Destination address.	*/
 	int		     dst_addr_len;  /**< Length of address.	*/
-	char		     dst_name[16];  /**< Destination address.	*/
+	char		     dst_name[PJ_INET6_ADDRSTRLEN]; /**< Destination address.	*/
 	int		     dst_port;	    /**< Destination port.	*/
     } tp_info;
Index: pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h	(revision 1601)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h	(revision 1602)
@@ -83,5 +83,15 @@
 
 /**
- * Attach UDP socket as a new transport and start the transport.
+ * Start IPv6 UDP transport.
+ */
+PJ_DECL(pj_status_t) pjsip_udp_transport_start6(pjsip_endpoint *endpt,
+						const pj_sockaddr_in6 *local,
+						const pjsip_host_port *a_name,
+						unsigned async_cnt,
+						pjsip_transport **p_transport);
+
+
+/**
+ * Attach IPv4 UDP socket as a new transport and start the transport.
  *
  * @param endpt		The SIP endpoint.
@@ -102,4 +112,27 @@
 						pjsip_transport **p_transport);
 
+
+/**
+ * Attach IPv4 or IPv6 UDP socket as a new transport and start the transport.
+ *
+ * @param endpt		The SIP endpoint.
+ * @param type		Transport type, which is PJSIP_TRANSPORT_UDP for IPv4
+ *			or PJSIP_TRANSPORT_UDP6 for IPv6 socket.
+ * @param sock		UDP socket to use.
+ * @param a_name	Published address (only the host and port portion is 
+ *			used).
+ * @param async_cnt	Number of simultaneous async operations.
+ * @param p_transport	Pointer to receive the transport.
+ *
+ * @return		PJ_SUCCESS when the transport has been successfully
+ *			started and registered to transport manager, or
+ *			the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_udp_transport_attach2(pjsip_endpoint *endpt,
+						 pjsip_transport_type_e type,
+						 pj_sock_t sock,
+						 const pjsip_host_port *a_name,
+						 unsigned async_cnt,
+						 pjsip_transport **p_transport);
 
 /**
Index: pjproject/trunk/pjsip/include/pjsip/sip_types.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 1601)
+++ pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 1602)
@@ -83,5 +83,14 @@
 
     /** Start of user defined transport */
-    PJSIP_TRANSPORT_START_OTHER
+    PJSIP_TRANSPORT_START_OTHER,
+
+    /** Start of IPv6 transports */
+    PJSIP_TRANSPORT_IPV6    = 128,
+
+    /** UDP over IPv6 */
+    PJSIP_TRANSPORT_UDP6 = PJSIP_TRANSPORT_UDP + PJSIP_TRANSPORT_IPV6,
+
+    /** TCP over IPv6 */
+    PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6
 
 } pjsip_transport_type_e;
Index: pjproject/trunk/pjsip/src/pjsip/sip_resolve.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_resolve.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsip/sip_resolve.c	(revision 1602)
@@ -22,4 +22,5 @@
 #include <pjlib-util/errno.h>
 #include <pjlib-util/srv_resolver.h>
+#include <pj/addr_resolv.h>
 #include <pj/array.h>
 #include <pj/assert.h>
@@ -138,19 +139,22 @@
 /*
  * Internal:
- *  determine if an address is a valid IP address.
- */
-static int is_str_ip(const pj_str_t *host)
-{
-    const char *p = host->ptr;
-    const char *end = ((const char*)host->ptr) + host->slen;
-
-    while (p != end) {
-	if (pj_isdigit(*p) || *p=='.') {
-	    ++p;
-	} else {
-	    return 0;
-	}
-    }
-    return 1;
+ *  determine if an address is a valid IP address, and if it is,
+ *  return the IP version (4 or 6).
+ */
+static int get_ip_addr_ver(const pj_str_t *host)
+{
+    pj_in_addr dummy;
+    pj_in6_addr dummy6;
+
+    /* First check with inet_aton() */
+    if (pj_inet_aton(host, &dummy) > 0)
+	return 4;
+
+    /* Then check if this is an IPv6 address */
+    if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS)
+	return 6;
+
+    /* Not an IP address */
+    return 0;
 }
 
@@ -167,10 +171,10 @@
     pjsip_server_addresses svr_addr;
     pj_status_t status = PJ_SUCCESS;
-    int is_ip_addr;
+    int ip_addr_ver;
     struct query *query;
     pjsip_transport_type_e type = target->type;
 
-    /* Is it IP address or hostname?. */
-    is_ip_addr = is_str_ip(&target->addr.host);
+    /* Is it IP address or hostname? And if it's an IP, which version? */
+    ip_addr_ver = get_ip_addr_ver(&target->addr.host);
 
     /* Set the transport type if not explicitly specified. 
@@ -178,5 +182,5 @@
      */
     if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
-	if (is_ip_addr || (target->addr.port != 0)) {
+	if (ip_addr_ver || (target->addr.port != 0)) {
 #if PJ_HAS_TCP
 	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
@@ -210,4 +214,8 @@
 	    }
 	}
+
+	/* Add IPv6 flag for IPv6 address */
+	if (ip_addr_ver == 6)
+	    type = (pjsip_transport_type_e)((int)type + PJSIP_TRANSPORT_IPV6);
     }
 
@@ -216,10 +224,13 @@
      * we can just finish the resolution now using pj_gethostbyname()
      */
-    if (is_ip_addr || resolver->res == NULL) {
+    if (ip_addr_ver || resolver->res == NULL) {
 
 	pj_in_addr ip_addr;
+	int af;
+	pj_addrinfo ai;
+	unsigned count;
 	pj_uint16_t srv_port;
 
-	if (!is_ip_addr) {
+	if (!ip_addr_ver) {
 	    PJ_LOG(5,(THIS_FILE, 
 		      "DNS resolver not available, target '%.*s:%d' type=%s "
@@ -239,11 +250,24 @@
 	}
 
-	/* This will eventually call pj_gethostbyname() if the host
-	 * is not an IP address.
-	 */
-	status = pj_sockaddr_in_init((pj_sockaddr_in*)&svr_addr.entry[0].addr,
-				      &target->addr.host, srv_port);
+	if (type & PJSIP_TRANSPORT_IPV6) {
+	    af = pj_AF_INET6();
+	} else {
+	    af = pj_AF_INET();
+	}
+
+	/* Resolve */
+	count = 1;
+	status = pj_getaddrinfo(af, &target->addr.host, &count, &ai);
 	if (status != PJ_SUCCESS)
 	    goto on_error;
+
+	svr_addr.entry[0].addr.addr.sa_family = (pj_uint16_t)af;
+	pj_memcpy(&svr_addr.entry[0].addr, &ai.ai_addr, sizeof(pj_sockaddr));
+
+	if (af == pj_AF_INET6()) {
+	    svr_addr.entry[0].addr.ipv6.sin6_port = pj_htons(srv_port);
+	} else {
+	    svr_addr.entry[0].addr.ipv4.sin_port = pj_htons(srv_port);
+	}
 
 	/* Call the callback. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 1602)
@@ -94,19 +94,100 @@
 struct transport_names_t
 {
-    pjsip_transport_type_e type;
-    pj_uint16_t		   port;
-    pj_str_t		   name;
-    unsigned		   flag;
-    char		   name_buf[16];
+    pjsip_transport_type_e type;	    /* Transport type	    */
+    pj_uint16_t		   port;	    /* Default port number  */
+    pj_str_t		   name;	    /* Id tag		    */
+    const char		  *description;	    /* Longer description   */
+    unsigned		   flag;	    /* Flags		    */
+    char		   name_buf[16];    /* For user's transport */
 } transport_names[16] = 
 {
-    { PJSIP_TRANSPORT_UNSPECIFIED, 0, {"Unspecified", 11}, 0},
-    { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}, PJSIP_TRANSPORT_DATAGRAM},
-    { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}, PJSIP_TRANSPORT_RELIABLE},
-    { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}, PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE},
-    { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}, PJSIP_TRANSPORT_RELIABLE},
-    { PJSIP_TRANSPORT_LOOP, 15060, {"LOOP", 4}, PJSIP_TRANSPORT_RELIABLE}, 
-    { PJSIP_TRANSPORT_LOOP_DGRAM, 15060, {"LOOP-DGRAM", 10}, PJSIP_TRANSPORT_DATAGRAM},
+    { 
+	PJSIP_TRANSPORT_UNSPECIFIED, 
+	0, 
+	{"Unspecified", 11}, 
+	"Unspecified", 
+	0
+    },
+    { 
+	PJSIP_TRANSPORT_UDP, 
+	5060, 
+	{"UDP", 3}, 
+	"UDP transport", 
+	PJSIP_TRANSPORT_DATAGRAM
+    },
+    { 
+	PJSIP_TRANSPORT_TCP, 
+	5060, 
+	{"TCP", 3}, 
+	"TCP transport", 
+	PJSIP_TRANSPORT_RELIABLE
+    },
+    { 
+	PJSIP_TRANSPORT_TLS, 
+	5061, 
+	{"TLS", 3}, 
+	"TLS transport", 
+	PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE
+    },
+    { 
+	PJSIP_TRANSPORT_SCTP, 
+	5060, 
+	{"SCTP", 4}, 
+	"SCTP transport", 
+	PJSIP_TRANSPORT_RELIABLE
+    },
+    { 
+	PJSIP_TRANSPORT_LOOP, 
+	15060, 
+	{"LOOP", 4}, 
+	"Loopback transport", 
+	PJSIP_TRANSPORT_RELIABLE
+    }, 
+    { 
+	PJSIP_TRANSPORT_LOOP_DGRAM, 
+	15060, 
+	{"LOOP-DGRAM", 10}, 
+	"Loopback datagram transport", 
+	PJSIP_TRANSPORT_DATAGRAM
+    },
+    { 
+	PJSIP_TRANSPORT_UDP6, 
+	5060, 
+	{"UDP", 3}, 
+	"UDP IPv6 transport", 
+	PJSIP_TRANSPORT_DATAGRAM
+    },
+    { 
+	PJSIP_TRANSPORT_TCP6, 
+	5060, 
+	{"TCP", 3}, 
+	"TCP IPv6 transport", 
+	PJSIP_TRANSPORT_RELIABLE
+    },
 };
+
+struct transport_names_t *get_tpname(pjsip_transport_type_e type)
+{
+    unsigned i;
+    for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
+	if (transport_names[i].type == type)
+	    return &transport_names[i];
+    }
+    pj_assert(!"Invalid transport type!");
+    return NULL;
+}
+
+
+/*
+ * Tools to get address string.
+ */
+static const char *addr_string(const pj_sockaddr_t *addr)
+{
+    static char str[PJ_INET6_ADDRSTRLEN];
+    pj_inet_ntop(((const pj_sockaddr*)addr)->addr.sa_family, 
+		 pj_sockaddr_get_addr(addr),
+		 str, sizeof(str));
+    return str;
+}
 
 
@@ -154,10 +235,4 @@
     unsigned i;
 
-    /* Sanity check. 
-     * Check that transport_names[] are indexed on transport type. 
-     */
-    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
-		     PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_UNSPECIFIED);
-
     if (name->slen == 0)
 	return PJSIP_TRANSPORT_UNSPECIFIED;
@@ -182,10 +257,4 @@
     unsigned i;
 
-    /* Sanity check. 
-     * Check that transport_names[] are indexed on transport type. 
-     */
-    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
-		     PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_UNSPECIFIED);
-
     /* Get the transport type for the specified flags. */
     for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
@@ -199,17 +268,19 @@
 }
 
+/*
+ * Get the socket address family of a given transport type.
+ */
+PJ_DEF(int) pjsip_transport_type_get_af(pjsip_transport_type_e type)
+{
+    if (type | PJSIP_TRANSPORT_IPV6)
+	return pj_AF_INET6();
+    else
+	return pj_AF_INET();
+}
+
 PJ_DEF(unsigned) pjsip_transport_get_flag_from_type(pjsip_transport_type_e type)
 {
-    /* Sanity check. 
-     * Check that transport_names[] are indexed on transport type. 
-     */
-    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
-		     PJSIP_TRANSPORT_UDP, 0);
-
-    /* Check that argument is valid. */
-    PJ_ASSERT_RETURN((unsigned)type < PJ_ARRAY_SIZE(transport_names), 0);
-
     /* Return transport flag. */
-    return transport_names[type].flag;
+    return get_tpname(type)->flag;
 }
 
@@ -219,15 +290,6 @@
 PJ_DEF(int) pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)
 {
-    /* Sanity check. 
-     * Check that transport_names[] are indexed on transport type. 
-     */
-    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
-		     PJSIP_TRANSPORT_UDP, 0);
-
-    /* Check that argument is valid. */
-    PJ_ASSERT_RETURN((unsigned)type < PJ_ARRAY_SIZE(transport_names), 5060);
-
     /* Return the port. */
-    return transport_names[type].port;
+    return get_tpname(type)->port;
 }
 
@@ -237,15 +299,15 @@
 PJ_DEF(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e type)
 {
-    /* Sanity check. 
-     * Check that transport_names[] are indexed on transport type. 
-     */
-    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
-		     PJSIP_TRANSPORT_UDP, "Unknown");
-
-    /* Check that argument is valid. */
-    PJ_ASSERT_RETURN((unsigned)type<PJ_ARRAY_SIZE(transport_names), "Unknown");
-
-    /* Return the port. */
-    return transport_names[type].name.ptr;
+    /* Return the name. */
+    return get_tpname(type)->name.ptr;
+}
+
+/*
+ * Get transport description.
+ */
+PJ_DEF(const char*) pjsip_transport_get_type_desc(pjsip_transport_type_e type)
+{
+    /* Return the description. */
+    return get_tpname(type)->description;
 }
 
@@ -557,13 +619,10 @@
     pj_memcpy(&tdata->tp_info.dst_addr, addr, addr_len);
     tdata->tp_info.dst_addr_len = addr_len;
-    if (((pj_sockaddr*)addr)->addr.sa_family == pj_AF_INET()) {
-	const char *str_addr;
-	str_addr = pj_inet_ntoa(((pj_sockaddr_in*)addr)->sin_addr);
-	pj_ansi_strcpy(tdata->tp_info.dst_name, str_addr);
-	tdata->tp_info.dst_port = pj_ntohs(((pj_sockaddr_in*)addr)->sin_port);
-    } else {
-	pj_ansi_strcpy(tdata->tp_info.dst_name, "<unknown>");
-	tdata->tp_info.dst_port = 0;
-    }
+
+    pj_inet_ntop(((pj_sockaddr*)addr)->addr.sa_family,
+		 pj_sockaddr_get_addr(addr),
+		 tdata->tp_info.dst_name,
+		 sizeof(tdata->tp_info.dst_name));
+    tdata->tp_info.dst_port = pj_sockaddr_get_port(addr);
 
     /* Distribute to modules. 
@@ -804,6 +863,6 @@
 		       tp->obj_name,
 		       pjsip_transport_get_type_name(tp->key.type),
-		       pj_inet_ntoa(((pj_sockaddr_in*)&tp->key.rem_addr)->sin_addr),
-		       pj_ntohs(((pj_sockaddr_in*)&tp->key.rem_addr)->sin_port)));
+		       addr_string(&tp->key.rem_addr),
+		       pj_sockaddr_get_port(&tp->key.rem_addr)));
 
     return PJ_SUCCESS;
@@ -1055,10 +1114,19 @@
     } else if ((flag & PJSIP_TRANSPORT_DATAGRAM) != 0) {
 	
-	pj_sockaddr_in remote;
+	pj_sockaddr remote;
+	int addr_len;
 	pjsip_transport *tp;
 
-	pj_sockaddr_in_init(&remote, NULL, 0);
+	pj_bzero(&remote, sizeof(remote));
+	if (type & PJSIP_TRANSPORT_IPV6) {
+	    addr_len = sizeof(pj_sockaddr_in6);
+	    remote.addr.sa_family = pj_AF_INET6();
+	} else {
+	    addr_len = sizeof(pj_sockaddr_in);
+	    remote.addr.sa_family = pj_AF_INET();
+	}
+
 	status = pjsip_tpmgr_acquire_transport(tpmgr, type, &remote,
-					       sizeof(remote), NULL, &tp);
+					       addr_len, NULL, &tp);
 
 	if (status == PJ_SUCCESS) {
@@ -1382,6 +1450,6 @@
     TRACE_((THIS_FILE,"Acquiring transport type=%s, remote=%s:%d",
 		       pjsip_transport_get_type_name(type),
-		       pj_inet_ntoa(((pj_sockaddr_in*)remote)->sin_addr),
-		       pj_ntohs(((pj_sockaddr_in*)remote)->sin_port)));
+		       addr_string(remote),
+		       pj_sockaddr_get_port(remote)));
 
     pj_lock_acquire(mgr->lock);
@@ -1463,22 +1531,21 @@
 		     type == PJSIP_TRANSPORT_LOOP_DGRAM)
 	    {
-		pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.rem_addr;
-
-		pj_bzero(addr, sizeof(pj_sockaddr_in));
-		key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
+		pj_sockaddr *addr = &key.rem_addr;
+
+		pj_bzero(addr, addr_len);
+		key_len = sizeof(key.type) + addr_len;
 		transport = (pjsip_transport*) 
 			    pj_hash_get(mgr->table, &key, key_len, NULL);
 	    }
-	    /* For datagram INET transports, try lookup with zero address.
+	    /* For datagram transports, try lookup with zero address.
 	     */
-	    else if ((flag & PJSIP_TRANSPORT_DATAGRAM) && 
-		     (remote_addr->addr.sa_family == pj_AF_INET())) 
+	    else if (flag & PJSIP_TRANSPORT_DATAGRAM)
 	    {
-		pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.rem_addr;
-
-		pj_bzero(addr, sizeof(pj_sockaddr_in));
-		addr->sin_family = pj_AF_INET();
-
-		key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
+		pj_sockaddr *addr = &key.rem_addr;
+
+		pj_bzero(addr, addr_len);
+		addr->addr.sa_family = remote_addr->addr.sa_family;
+
+		key_len = sizeof(key.type) + addr_len;
 		transport = (pjsip_transport*)
 			    pj_hash_get(mgr->table, &key, key_len, NULL);
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 1602)
@@ -290,11 +290,11 @@
 	 */
 	if (listener_addr->sin_addr.s_addr == 0) {
-	    pj_in_addr hostip;
-
-	    status = pj_gethostip(&hostip);
+	    pj_sockaddr hostip;
+
+	    status = pj_gethostip(pj_AF_INET(), &hostip);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
 
-	    listener_addr->sin_addr = hostip;
+	    listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr;
 	}
 
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 1602)
@@ -143,6 +143,5 @@
 	if (bytes_read > MIN_SIZE) {
 	    pj_size_t size_eaten;
-	    const pj_sockaddr_in *src_addr = 
-		(pj_sockaddr_in*)&rdata->pkt_info.src_addr;
+	    const pj_sockaddr *src_addr = &rdata->pkt_info.src_addr;
 
 	    /* Init pkt_info part. */
@@ -150,7 +149,15 @@
 	    rdata->pkt_info.zero = 0;
 	    pj_gettimeofday(&rdata->pkt_info.timestamp);
-	    pj_ansi_strcpy(rdata->pkt_info.src_name,
-			   pj_inet_ntoa(src_addr->sin_addr));
-	    rdata->pkt_info.src_port = pj_ntohs(src_addr->sin_port);
+	    if (src_addr->addr.sa_family == pj_AF_INET()) {
+		pj_ansi_strcpy(rdata->pkt_info.src_name,
+			       pj_inet_ntoa(src_addr->ipv4.sin_addr));
+		rdata->pkt_info.src_port = pj_ntohs(src_addr->ipv4.sin_port);
+	    } else {
+		pj_inet_ntop(pj_AF_INET6(), 
+			     pj_sockaddr_get_addr(&rdata->pkt_info.src_addr),
+			     rdata->pkt_info.src_name,
+			     sizeof(rdata->pkt_info.src_name));
+		rdata->pkt_info.src_port = pj_ntohs(src_addr->ipv6.sin6_port);
+	    }
 
 	    size_eaten = 
@@ -413,21 +420,30 @@
 
 /* Create socket */
-static pj_status_t create_socket(const pj_sockaddr_in *local_a,
-				 pj_sock_t *p_sock)
+static pj_status_t create_socket(int af, const pj_sockaddr_t *local_a,
+				 int addr_len, pj_sock_t *p_sock)
 {
     pj_sock_t sock;
     pj_sockaddr_in tmp_addr;
+    pj_sockaddr_in6 tmp_addr6;
     pj_status_t status;
 
-    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock);
+    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
     if (status != PJ_SUCCESS)
 	return status;
 
     if (local_a == NULL) {
-	pj_sockaddr_in_init(&tmp_addr, NULL, 0);
-	local_a = &tmp_addr;
-    }
-
-    status = pj_sock_bind(sock, local_a, sizeof(*local_a));
+	if (af == pj_AF_INET6()) {
+	    pj_bzero(&tmp_addr6, sizeof(tmp_addr6));
+	    tmp_addr6.sin6_family = (pj_uint16_t)af;
+	    local_a = &tmp_addr6;
+	    addr_len = sizeof(tmp_addr6);
+	} else {
+	    pj_sockaddr_in_init(&tmp_addr, NULL, 0);
+	    local_a = &tmp_addr;
+	    addr_len = sizeof(tmp_addr);
+	}
+    }
+
+    status = pj_sock_bind(sock, local_a, addr_len);
     if (status != PJ_SUCCESS) {
 	pj_sock_close(sock);
@@ -443,7 +459,8 @@
 static pj_status_t get_published_name(pj_sock_t sock,
 				      char hostbuf[],
+				      int hostbufsz,
 				      pjsip_host_port *bound_name)
 {
-    pj_sockaddr_in tmp_addr;
+    pj_sockaddr tmp_addr;
     int addr_len;
     pj_status_t status;
@@ -455,23 +472,34 @@
 
     bound_name->host.ptr = hostbuf;
-    bound_name->port = pj_ntohs(tmp_addr.sin_port);
-
-    /* If bound address specifies "0.0.0.0", get the IP address
-     * of local hostname.
-     */
-    if (tmp_addr.sin_addr.s_addr == PJ_INADDR_ANY) {
-	pj_in_addr hostip;
-
-	status = pj_gethostip(&hostip);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	pj_strcpy2(&bound_name->host, pj_inet_ntoa(hostip));
+    if (tmp_addr.addr.sa_family == pj_AF_INET()) {
+	bound_name->port = pj_ntohs(tmp_addr.ipv4.sin_port);
+
+	/* If bound address specifies "0.0.0.0", get the IP address
+	 * of local hostname.
+	 */
+	if (tmp_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) {
+	    pj_sockaddr hostip;
+
+	    status = pj_gethostip(pj_AF_INET(), &hostip);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    pj_strcpy2(&bound_name->host, pj_inet_ntoa(hostip.ipv4.sin_addr));
+	} else {
+	    /* Otherwise use bound address. */
+	    pj_strcpy2(&bound_name->host, 
+		       pj_inet_ntoa(tmp_addr.ipv4.sin_addr));
+	    status = PJ_SUCCESS;
+	}
+
     } else {
-	/* Otherwise use bound address. */
-	pj_strcpy2(&bound_name->host, pj_inet_ntoa(tmp_addr.sin_addr));
-    }
-
-    return PJ_SUCCESS;
+	bound_name->port = pj_ntohs(tmp_addr.ipv6.sin6_port);
+	status = pj_inet_ntop(tmp_addr.addr.sa_family, 
+			      pj_sockaddr_get_addr(&tmp_addr),
+			      hostbuf, hostbufsz);
+    }
+
+
+    return status;
 }
 
@@ -481,4 +509,5 @@
 {
     enum { INFO_LEN = 80 };
+    char local_addr[PJ_INET6_ADDRSTRLEN];
 
     pj_assert(a_name->host.slen != 0);
@@ -491,8 +520,13 @@
 	tp->base.info = (char*) pj_pool_alloc(tp->base.pool, INFO_LEN);
     }
+
+    pj_inet_ntop(tp->base.local_addr.addr.sa_family,
+		 pj_sockaddr_get_addr(&tp->base.local_addr), 
+		 local_addr, sizeof(local_addr));
+
     pj_ansi_snprintf( 
 	tp->base.info, INFO_LEN, "udp %s:%d [published as %s:%d]",
-	pj_inet_ntoa(((pj_sockaddr_in*)&tp->base.local_addr)->sin_addr),
-	pj_ntohs(((pj_sockaddr_in*)&tp->base.local_addr)->sin_port),
+	local_addr,
+	pj_sockaddr_get_port(&tp->base.local_addr),
 	tp->base.local_name.host.ptr,
 	tp->base.local_name.port);
@@ -596,12 +630,14 @@
  * Attach UDP socket and start transport.
  */
-PJ_DEF(pj_status_t) pjsip_udp_transport_attach( pjsip_endpoint *endpt,
-						pj_sock_t sock,
-						const pjsip_host_port *a_name,
-						unsigned async_cnt,
-						pjsip_transport **p_transport)
+static pj_status_t transport_attach( pjsip_endpoint *endpt,
+				     pjsip_transport_type_e type,
+				     pj_sock_t sock,
+				     const pjsip_host_port *a_name,
+				     unsigned async_cnt,
+				     pjsip_transport **p_transport)
 {
     pj_pool_t *pool;
     struct udp_transport *tp;
+    const char *format;
     unsigned i;
     pj_status_t status;
@@ -610,6 +646,12 @@
 		     PJ_EINVAL);
 
+    /* Object name. */
+    if (type & PJSIP_TRANSPORT_IPV6)
+	format = "udpv6%p";
+    else
+	format = "udp%p";
+
     /* Create pool. */
-    pool = pjsip_endpt_create_pool(endpt, "udp%p", PJSIP_POOL_LEN_TRANSPORT, 
+    pool = pjsip_endpt_create_pool(endpt, format, PJSIP_POOL_LEN_TRANSPORT, 
 				   PJSIP_POOL_INC_TRANSPORT);
     if (!pool)
@@ -622,7 +664,5 @@
     tp->base.pool = pool;
 
-    /* Object name. */
-    pj_ansi_snprintf(tp->base.obj_name, sizeof(tp->base.obj_name), 
-		     "udp%p", tp);
+    pj_memcpy(tp->base.obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);
 
     /* Init reference counter. */
@@ -632,13 +672,15 @@
 
     /* Init lock. */
-    status = pj_lock_create_recursive_mutex(pool, "udp%p", &tp->base.lock);
+    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, 
+					    &tp->base.lock);
     if (status != PJ_SUCCESS)
 	goto on_error;
 
     /* Set type. */
-    tp->base.key.type = PJSIP_TRANSPORT_UDP;
+    tp->base.key.type = type;
 
     /* Remote address is left zero (except the family) */
-    tp->base.key.rem_addr.addr.sa_family = pj_AF_INET();
+    tp->base.key.rem_addr.addr.sa_family = (pj_uint16_t)
+	((type & PJSIP_TRANSPORT_IPV6) ? pj_AF_INET6() : pj_AF_INET());
 
     /* Type name. */
@@ -646,9 +688,9 @@
 
     /* Transport flag */
-    tp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
+    tp->base.flag = pjsip_transport_get_flag_from_type(type);
 
 
     /* Length of addressess. */
-    tp->base.addr_len = sizeof(pj_sockaddr_in);
+    tp->base.addr_len = sizeof(tp->base.local_addr);
 
     /* Init local address. */
@@ -659,5 +701,8 @@
 
     /* Init remote name. */
-    tp->base.remote_name.host = pj_str("0.0.0.0");
+    if (type == PJSIP_TRANSPORT_UDP)
+	tp->base.remote_name.host = pj_str("0.0.0.0");
+    else
+	tp->base.remote_name.host = pj_str("::0");
     tp->base.remote_name.port = 0;
 
@@ -724,5 +769,6 @@
 
     PJ_LOG(4,(tp->base.obj_name, 
-	      "SIP UDP transport started, published address is %.*s:%d",
+	      "SIP %s started, published address is %.*s:%d",
+	      pjsip_transport_get_type_desc((pjsip_transport_type_e)tp->base.key.type),
 	      (int)tp->base.local_name.host.slen,
 	      tp->base.local_name.host.ptr,
@@ -734,4 +780,26 @@
     udp_destroy((pjsip_transport*)tp);
     return status;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_udp_transport_attach( pjsip_endpoint *endpt,
+						pj_sock_t sock,
+						const pjsip_host_port *a_name,
+						unsigned async_cnt,
+						pjsip_transport **p_transport)
+{
+    return transport_attach(endpt, PJSIP_TRANSPORT_UDP, sock, a_name,
+			    async_cnt, p_transport);
+}
+
+PJ_DEF(pj_status_t) pjsip_udp_transport_attach2( pjsip_endpoint *endpt,
+						 pjsip_transport_type_e type,
+						 pj_sock_t sock,
+						 const pjsip_host_port *a_name,
+						 unsigned async_cnt,
+						 pjsip_transport **p_transport)
+{
+    return transport_attach(endpt, type, sock, a_name,
+			    async_cnt, p_transport);
 }
 
@@ -749,10 +817,11 @@
     pj_sock_t sock;
     pj_status_t status;
-    char addr_buf[16];
+    char addr_buf[PJ_INET6_ADDRSTRLEN];
     pjsip_host_port bound_name;
 
     PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
 
-    status = create_socket(local_a, &sock);
+    status = create_socket(pj_AF_INET(), local_a, sizeof(pj_sockaddr_in), 
+			   &sock);
     if (status != PJ_SUCCESS)
 	return status;
@@ -762,5 +831,6 @@
 	 * Build a name based on bound address.
 	 */
-	status = get_published_name(sock, addr_buf, &bound_name);
+	status = get_published_name(sock, addr_buf, sizeof(addr_buf), 
+				    &bound_name);
 	if (status != PJ_SUCCESS) {
 	    pj_sock_close(sock);
@@ -775,4 +845,45 @@
 }
 
+
+/*
+ * pjsip_udp_transport_start()
+ *
+ * Create a UDP socket in the specified address and start a transport.
+ */
+PJ_DEF(pj_status_t) pjsip_udp_transport_start6(pjsip_endpoint *endpt,
+					       const pj_sockaddr_in6 *local_a,
+					       const pjsip_host_port *a_name,
+					       unsigned async_cnt,
+					       pjsip_transport **p_transport)
+{
+    pj_sock_t sock;
+    pj_status_t status;
+    char addr_buf[PJ_INET_ADDRSTRLEN];
+    pjsip_host_port bound_name;
+
+    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
+
+    status = create_socket(pj_AF_INET6(), local_a, sizeof(pj_sockaddr_in6), 
+			   &sock);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if (a_name == NULL) {
+	/* Address name is not specified. 
+	 * Build a name based on bound address.
+	 */
+	status = get_published_name(sock, addr_buf, sizeof(addr_buf), 
+				    &bound_name);
+	if (status != PJ_SUCCESS) {
+	    pj_sock_close(sock);
+	    return status;
+	}
+
+	a_name = &bound_name;
+    }
+
+    return pjsip_udp_transport_attach( endpt, sock, a_name, async_cnt, 
+				       p_transport);
+}
 
 /*
@@ -870,5 +981,5 @@
 
     if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) {
-	char addr_buf[16];
+	char addr_buf[PJ_INET_ADDRSTRLEN];
 	pjsip_host_port bound_name;
 
@@ -891,5 +1002,6 @@
 	/* Create the socket if it's not specified */
 	if (sock == PJ_INVALID_SOCKET) {
-	    status = create_socket(local, &sock);
+	    status = create_socket(pj_AF_INET(), local, 
+				   sizeof(pj_sockaddr_in), &sock);
 	    if (status != PJ_SUCCESS)
 		return status;
@@ -900,5 +1012,6 @@
 	 */
 	if (a_name == NULL) {
-	    status = get_published_name(sock, addr_buf, &bound_name);
+	    status = get_published_name(sock, addr_buf, sizeof(addr_buf),
+					&bound_name);
 	    if (status != PJ_SUCCESS) {
 		pj_sock_close(sock);
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1602)
@@ -1183,15 +1183,30 @@
 
 /*
+ * Tools to get address string.
+ */
+static const char *addr_string(const pj_sockaddr_t *addr)
+{
+    static char str[128];
+    str[0] = '\0';
+    pj_inet_ntop(((const pj_sockaddr*)addr)->addr.sa_family, 
+		 pj_sockaddr_get_addr(addr),
+		 str, sizeof(str));
+    return str;
+}
+
+/*
  * Create and initialize SIP socket (and possibly resolve public
  * address via STUN, depending on config).
  */
-static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr,
+static pj_status_t create_sip_udp_sock(int af,
+				       const pj_str_t *bind_param,
 				       int port,
 				       pj_sock_t *p_sock,
-				       pj_sockaddr_in *p_pub_addr)
-{
-    char ip_addr[32];
+				       pj_sockaddr *p_pub_addr)
+{
+    char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
     pj_str_t stun_srv;
     pj_sock_t sock;
+    pj_sockaddr bind_addr;
     pj_status_t status;
 
@@ -1203,5 +1218,19 @@
     }
 
-    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock);
+    /* Initialize bound address */
+    if (bind_param->slen) {
+	status = pj_sockaddr_init(af, &bind_addr, bind_param, 
+				  (pj_uint16_t)port);
+	if (status != PJ_SUCCESS) {
+	    pjsua_perror(THIS_FILE, 
+			 "Unable to resolve transport bound address", 
+			 status);
+	    return status;
+	}
+    } else {
+	pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
+    }
+
+    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "socket() error", status);
@@ -1209,6 +1238,5 @@
     }
 
-    status = pj_sock_bind_in(sock, pj_ntohl(bound_addr.s_addr), 
-			     (pj_uint16_t)port);
+    status = pj_sock_bind(sock, &bind_addr, sizeof(bind_addr));
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "bind() error", status);
@@ -1219,5 +1247,5 @@
     /* If port is zero, get the bound port */
     if (port == 0) {
-	pj_sockaddr_in bound_addr;
+	pj_sockaddr bound_addr;
 	int namelen = sizeof(bound_addr);
 	status = pj_sock_getsockname(sock, &bound_addr, &namelen);
@@ -1228,10 +1256,10 @@
 	}
 
-	port = pj_ntohs(bound_addr.sin_port);
+	port = pj_sockaddr_get_port(&bound_addr);
     }
 
     if (pjsua_var.stun_srv.addr.sa_family != 0) {
-	pj_ansi_strcpy(ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
-	stun_srv = pj_str(ip_addr);
+	pj_ansi_strcpy(stun_ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
+	stun_srv = pj_str(stun_ip_addr);
     } else {
 	stun_srv.slen = 0;
@@ -1241,11 +1269,11 @@
      * the name of local host.
      */
-    if (p_pub_addr->sin_addr.s_addr != 0) {
+    if (pj_sockaddr_has_addr(p_pub_addr)) {
 	/*
 	 * Public address is already specified, no need to resolve the 
 	 * address, only set the port.
 	 */
-	if (p_pub_addr->sin_port == 0)
-	    p_pub_addr->sin_port = pj_htons((pj_uint16_t)port);
+	if (pj_sockaddr_get_port(p_pub_addr) == 0)
+	    pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
 
     } else if (stun_srv.slen) {
@@ -1253,8 +1281,14 @@
 	 * STUN is specified, resolve the address with STUN.
 	 */
+	if (af != pj_AF_INET()) {
+	    pjsua_perror(THIS_FILE, "Cannot use STUN", PJ_EAFNOTSUP);
+	    pj_sock_close(sock);
+	    return PJ_EAFNOTSUP;
+	}
+
 	status = pjstun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock,
 				         &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
 					 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
-				         p_pub_addr);
+				         &p_pub_addr->ipv4);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
@@ -1264,8 +1298,7 @@
 
     } else {
-
-	pj_bzero(p_pub_addr, sizeof(pj_sockaddr_in));
-
-	status = pj_gethostip(&p_pub_addr->sin_addr);
+	pj_bzero(p_pub_addr, sizeof(pj_sockaddr));
+
+	status = pj_gethostip(af, p_pub_addr);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
@@ -1274,6 +1307,6 @@
 	}
 
-	p_pub_addr->sin_family = pj_AF_INET();
-	p_pub_addr->sin_port = pj_htons((pj_uint16_t)port);
+	p_pub_addr->addr.sa_family = (pj_uint16_t)af;
+	pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
     }
 
@@ -1281,6 +1314,6 @@
 
     PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
-	      pj_inet_ntoa(p_pub_addr->sin_addr),
-	      (int)pj_ntohs(p_pub_addr->sin_port)));
+	      addr_string(p_pub_addr),
+	      (int)pj_sockaddr_get_port(p_pub_addr)));
 
     return PJ_SUCCESS;
@@ -1314,12 +1347,12 @@
 
     /* Create the transport */
-    if (type == PJSIP_TRANSPORT_UDP) {
+    if (type & PJSIP_TRANSPORT_UDP) {
 	/*
-	 * Create UDP transport.
+	 * Create UDP transport (IPv4 or IPv6).
 	 */
 	pjsua_transport_config config;
+	char hostbuf[PJ_INET6_ADDRSTRLEN];
 	pj_sock_t sock = PJ_INVALID_SOCKET;
-	pj_sockaddr_in bound_addr;
-	pj_sockaddr_in pub_addr;
+	pj_sockaddr pub_addr;
 	pjsip_host_port addr_name;
 
@@ -1330,20 +1363,10 @@
 	}
 
-	/* Initialize bound address, if any */
-	bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
-	if (cfg->bound_addr.slen) {
-	    status = pj_sockaddr_in_set_str_addr(&bound_addr,&cfg->bound_addr);
-	    if (status != PJ_SUCCESS) {
-		pjsua_perror(THIS_FILE, 
-			     "Unable to resolve transport bound address", 
-			     status);
-		goto on_return;
-	    }
-	}
-
 	/* Initialize the public address from the config, if any */
-	pj_sockaddr_in_init(&pub_addr, NULL, (pj_uint16_t)cfg->port);
+	pj_sockaddr_init(pjsip_transport_type_get_af(type), &pub_addr, 
+			 NULL, (pj_uint16_t)cfg->port);
 	if (cfg->public_addr.slen) {
-	    status = pj_sockaddr_in_set_str_addr(&pub_addr, &cfg->public_addr);
+	    status = pj_sockaddr_set_str_addr(pjsip_transport_type_get_af(type),
+					      &pub_addr, &cfg->public_addr);
 	    if (status != PJ_SUCCESS) {
 		pjsua_perror(THIS_FILE, 
@@ -1357,16 +1380,17 @@
 	 * (only when public address is not specified).
 	 */
-	status = create_sip_udp_sock(bound_addr.sin_addr, cfg->port, 
+	status = create_sip_udp_sock(pjsip_transport_type_get_af(type),
+				     &cfg->bound_addr, cfg->port,
 				     &sock, &pub_addr);
 	if (status != PJ_SUCCESS)
 	    goto on_return;
 
-	addr_name.host = pj_str(pj_inet_ntoa(pub_addr.sin_addr));
-	addr_name.port = pj_ntohs(pub_addr.sin_port);
+	pj_ansi_strcpy(hostbuf, addr_string(&pub_addr));
+	addr_name.host = pj_str(hostbuf);
+	addr_name.port = pj_sockaddr_get_port(&pub_addr);
 
 	/* Create UDP transport */
-	status = pjsip_udp_transport_attach( pjsua_var.endpt, sock,
-					     &addr_name, 1, 
-					     &tp);
+	status = pjsip_udp_transport_attach2(pjsua_var.endpt, type, sock,
+					     &addr_name, 1, &tp);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Error creating SIP UDP transport", 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1601)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1602)
@@ -347,13 +347,13 @@
 
 	} else {
-	    pj_in_addr addr;
+	    pj_sockaddr addr;
 
 	    /* Get local IP address. */
-	    status = pj_gethostip(&addr);
+	    status = pj_gethostip(pj_AF_INET(), &addr);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
 
 	    for (i=0; i<2; ++i)
-		mapped_addr[i].sin_addr = addr;
+		mapped_addr[i].sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;
 
 	    mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);
