Initial commit for ticket #950: QoS support:
 - implementation:
     - PJLIB (sock_qos*.*)
 - added QoS support in:
     - SIP UDP transport, 
     - SIP TCP transport,
     - media UDP transport (done in pjsua-lib), 
     - pjnath ICE stream transport,
     - pjnath STUN socket,
     - pjnath TURN client
 - added QoS options in pjsua-lib:
     - QoS fields in pjsua_transport_config
 - added "--set-qos" parameter in pjsua

Notes:
 - QoS in TLS transport is not yet implemented, waiting for #957
 - build ok on VS6, VS2005 (multiple targets), Carbide, and Mingw
 - no run-time testing yet



git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2966 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/build.symbian/pjlib.mmp b/build.symbian/pjlib.mmp
index 1385b97..14576e3 100644
--- a/build.symbian/pjlib.mmp
+++ b/build.symbian/pjlib.mmp
@@ -50,6 +50,7 @@
 SOURCE		rand.c
 SOURCE		rbtree.c
 SOURCE		sock_common.c
+SOURCE		sock_qos_common.c
 SOURCE		types.c
 
 
@@ -75,6 +76,7 @@
 SOURCE		ssl_sock_symbian.cpp
 SOURCE		sock_symbian.cpp
 SOURCE		sock_select_symbian.cpp
+SOURCE		sock_qos_symbian.cpp
 SOURCE		timer_symbian.cpp
 SOURCE		unicode_symbian.cpp
 
diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile
index c3819f3..439c7fa 100644
--- a/pjlib/build/Makefile
+++ b/pjlib/build/Makefile
@@ -25,7 +25,8 @@
 	activesock.o array.o config.o ctype.o errno.o except.o fifobuf.o \
 	guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \
 	pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \
-	rbtree.o sock_common.o string.o timer.o types.o
+	rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \
+	string.o timer.o types.o
 export PJLIB_CFLAGS += $(_CFLAGS)
 
 ###############################################################################
diff --git a/pjlib/build/pjlib.dsp b/pjlib/build/pjlib.dsp
index 39d800c..2b04256 100644
--- a/pjlib/build/pjlib.dsp
+++ b/pjlib/build/pjlib.dsp
@@ -341,6 +341,14 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\src\pj\sock_qos_bsd.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\src\pj\sock_qos_common.c

+# End Source File

+# Begin Source File

+

 SOURCE=..\src\pj\sock_select.c

 # End Source File

 # Begin Source File

@@ -589,6 +597,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\include\pj\sock_qos.h

+# End Source File

+# Begin Source File

+

 SOURCE=..\include\pj\sock_select.h

 # End Source File

 # Begin Source File

diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj
index 2f03603..7f4ee00 100644
--- a/pjlib/build/pjlib.vcproj
+++ b/pjlib/build/pjlib.vcproj
Binary files differ
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index 0ae8997..71ca8a0 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -748,6 +748,37 @@
 #   define PJ_HAS_STRICMP_ALNUM	    0
 #endif
 
+
+/*
+ * Types of QoS backend implementation.
+ */
+
+/** 
+ * Dummy QoS backend implementation, will always return error on all
+ * the APIs.
+ */
+#define PJ_QOS_DUMMY	    1
+
+/** QoS backend based on setsockopt(IP_TOS) */
+#define PJ_QOS_BSD	    2
+
+/** QoS backend for Windows Mobile 6 */
+#define PJ_QOS_WM	    3
+
+/** QoS backend for Symbian */
+#define PJ_QOS_SYMBIAN	    4
+
+/**
+ * Force the use of some QoS backend API for some platforms.
+ */
+#ifndef PJ_QOS_IMPLEMENTATION
+#   if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE && _WIN32_WCE >= 0x502
+	/* Windows Mobile 6 or later */
+#	define PJ_QOS_IMPLEMENTATION    PJ_QOS_WM
+#   endif
+#endif
+
+
 /** @} */
 
 /********************************************************************
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index a72b63e..3245367 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -297,6 +297,10 @@
  *  @see pj_SO_REUSEADDR */
 extern const pj_uint16_t PJ_SO_REUSEADDR;
 
+/** Set the protocol-defined priority for all packets to be sent on socket.
+ */
+extern const pj_uint16_t PJ_SO_PRIORITY;
+
 /** IP multicast interface. @see pj_IP_MULTICAST_IF() */
 extern const pj_uint16_t PJ_IP_MULTICAST_IF;
  
@@ -329,6 +333,9 @@
     /** Get #PJ_SO_REUSEADDR constant */
     PJ_DECL(pj_uint16_t) pj_SO_REUSEADDR(void);
 
+    /** Get #PJ_SO_PRIORITY constant */
+    PJ_DECL(pj_uint16_t) pj_SO_PRIORITY(void);
+
     /** Get #PJ_IP_MULTICAST_IF constant */
     PJ_DECL(pj_uint16_t) pj_IP_MULTICAST_IF(void);
 
@@ -359,6 +366,9 @@
     /** Get #PJ_SO_REUSEADDR constant */
 #   define pj_SO_REUSEADDR() PJ_SO_REUSEADDR
 
+    /** Get #PJ_SO_PRIORITY constant */
+#   define pj_SO_PRIORITY() PJ_SO_PRIORITY
+
     /** Get #PJ_IP_MULTICAST_IF constant */
 #   define pj_IP_MULTICAST_IF()    PJ_IP_MULTICAST_IF
 
diff --git a/pjlib/include/pj/sock_qos.h b/pjlib/include/pj/sock_qos.h
new file mode 100644
index 0000000..12dd4b8
--- /dev/null
+++ b/pjlib/include/pj/sock_qos.h
@@ -0,0 +1,427 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 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 
+ */
+#ifndef __PJ_SOCK_QOS_H__
+#define __PJ_SOCK_QOS_H__
+
+/**
+ * @file sock_qos.h
+ * @brief Socket QoS API
+ */
+
+#include <pj/sock.h>
+
+PJ_BEGIN_DECL 
+
+
+/**
+ * @defgroup socket_qos Socket Quality of Service (QoS) API
+ * @ingroup PJ_SOCK
+ * @{
+
+
+    \section intro QoS Technologies
+
+    QoS settings are available for both Layer 2 and 3 of TCP/IP protocols:
+
+    \subsection intro_ieee8021p Layer 2: IEEE 802.1p for Ethernet
+
+    IEEE 802.1p tagging will mark frames sent by a host for prioritized 
+    delivery using a 3-bit Priority field in the virtual local area network 
+    (VLAN) header of the Ethernet frame. The VLAN header is placed inside 
+    the Ethernet header, between the Source Address field and either the 
+    Length field (for an IEEE 802.3 frame) or the EtherType field (for an
+    Ethernet II frame).
+
+    \subsection intro_wmm Layer 2: WMM
+
+    At the Network Interface layer for IEEE 802.11 wireless, the Wi-Fi 
+    Alliance certification for Wi-Fi Multimedia (WMM) defines four access 
+    categories for prioritizing network traffic. These access categories 
+    are (in order of highest to lowest priority) voice, video, best-effort, 
+    and background. Host support for WMM prioritization requires that both 
+    wireless network adapters and their drivers support WMM. Wireless 
+    access points (APs) must have WMM enabled.
+
+    \subsection intro_dscp Layer 3: DSCP
+
+    At the Internet layer, you can use Differentiated Services/Diffserv and
+    set the value of the Differentiated Services Code Point (DSCP) in the 
+    IP header. As defined in RFC 2472, the DSCP value is the high-order 6 bits
+    of the IP version 4 (IPv4) TOS field and the IP version 6 (IPv6) Traffic 
+    Class field.
+
+    \subsection intro_other Layer 3: Other
+
+    Other mechanisms exist (such as RSVP, IntServ) but this will not be 
+    implemented.
+
+
+    \section availability QoS Availability
+
+    \subsection linux Linux
+
+    DSCP is available via IP TOS option.
+
+    Ethernet 802.1p tagging is done by setting setsockopt(SO_PRIORITY) option 
+    of the socket, then with the set_egress_map option of the vconfig utility 
+    to convert this to set vlan-qos field of the packet.
+
+    WMM is not known to be available.
+
+    \subsection windows Windows and Windows Mobile
+
+    (It's a mess!)
+
+    DSCP is settable with setsockopt() on Windows 2000 or older, but Windows 
+    would silently ignore this call on WinXP or later, unless administrator 
+    modifies the registry. On Windows 2000, Windows XP, and Windows Server 
+    2003, GQoS (Generic QoS) API is the standard API, but this API may not be
+    supported in the future. On Vista and Windows 7, the is a new QoS2 API, 
+    also known as Quality Windows Audio-Video Experience (qWAVE).
+
+    IEEE 802.1p tagging is available via Traffic Control (TC) API, available
+    on Windows XP SP2, but this needs administrator access. For Vista and 
+    later, it's in qWAVE.
+
+    WMM is available for mobile platforms on Windows Mobile 6 platform and 
+    Windows Embedded CE 6, via setsockopt(IP_DSCP_TRAFFIC_TYPE). qWAVE 
+    supports this as well.
+
+    \subsection symbian Symbian S60 3rd Ed
+
+    Both DSCP and WMM is supported via RSocket::SetOpt() with will set both 
+    Layer 2 and Layer 3 QoS settings accordingly. Internally, PJLIB sets the
+    DSCP field of the socket, and based on certain DSCP values mapping,
+    Symbian will set the WMM tag accordingly.
+
+    \section api PJLIB's QoS API Abstraction
+
+    Based on the above, the following API is implemented.
+
+    Declare the following "standard" traffic types.
+
+    \code
+     typedef enum pj_qos_type
+     {
+	PJ_QOS_TYPE_BEST_EFFORT,
+	PJ_QOS_TYPE_BACKGROUND,
+	PJ_QOS_TYPE_VIDEO,
+	PJ_QOS_TYPE_VOICE,
+	PJ_QOS_TYPE_CONTROL
+     } pj_qos_type;
+    \endcode
+
+    The traffic classes above will determine how the Layer 2 and 3 QoS 
+    settings will be used. The standard mapping between the classes above 
+    to the corresponding Layer 2 and 3 settings are as follows:
+
+    \code
+    =================================================================
+    PJLIB Traffic Type 	IP DSCP 	WMM 		    802.1p
+    -----------------------------------------------------------------
+    BEST_EFFORT 	0x00 		BE (Bulk Effort) 	0
+    BACKGROUND 		0x08 		BK (Bulk) 		2
+    VIDEO 		0x28 		VI (Video) 		5
+    VOICE 		0x30 		VO (Voice) 		6
+    CONTROL 		0x38 		VO (Voice) 		7
+    =================================================================
+    \endcode
+
+    There are two sets of API provided to manipulate the QoS parameters.
+
+    \subsection portable_api Portable API
+
+    The first set of API is:
+
+    \code
+     // Set QoS parameters
+     PJ_DECL(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					       pj_qos_type val);
+
+     // Get QoS parameters
+     PJ_DECL(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					       pj_qos_type *p_val);
+    \endcode
+
+    The API will set the traffic type according to the DSCP class, for both 
+    Layer 2 and Layer 3 QoS settings, where it's available. If any of the 
+    layer QoS setting is not settable, the API will silently ignore it. 
+    If both layers are not setable, the API will return error.
+
+    The API above is the recommended use of QoS, since it is the most 
+    portable across all platforms.
+
+    \subsection detail_api Fine Grained Control API
+
+    The second set of API is intended for application that wants to fine 
+    tune the QoS parameters.
+
+    The Layer 2 and 3 QoS parameters are stored in pj_qos_params structure:
+
+    \code
+     typedef enum pj_qos_flag
+     {
+	PJ_QOS_PARAM_HAS_DSCP = 1,
+	PJ_QOS_PARAM_HAS_802_1_P = 2,
+	PJ_QOS_PARAM_HAS_WMM = 4
+     } pj_qos_flag;
+
+     typedef enum pj_qos_wmm_prio
+     {
+	PJ_QOS_WMM_PRIO_BULK_EFFORT,
+	PJ_QOS_WMM_PRIO_BULK,
+	PJ_QOS_WMM_PRIO_VIDEO,
+	PJ_QOS_WMM_PRIO_VOICE
+     } pj_qos_wmm_prio;
+
+     typedef struct pj_qos_params
+     {
+	pj_uint8_t      flags;    // Determines which values to 
+				  // set, bitmask of pj_qos_flag
+	pj_uint8_t      dscp_val; // DSCP value to set
+	pj_uint8_t      so_prio;  // SO_PRIORITY value
+	pj_qos_wmm_prio wmm_prio; // WMM priority value
+     } pj_qos_params;
+    \endcode
+
+    The second set of API with more fine-grained control over the parameters 
+    are:
+
+    \code
+     // Retrieve QoS params for the specified traffic type
+     PJ_DECL(pj_status_t) pj_qos_get_params(pj_qos_type type, 
+					    pj_qos_params *p);
+
+     // Set QoS parameters to the socket
+     PJ_DECL(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+						 const pj_qos_params *p);
+
+     // Get QoS parameters from the socket
+     PJ_DECL(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+						 pj_qos_params *p);
+    \endcode
+
+
+    Important:
+
+    The pj_sock_set/get_qos_params() APIs are not portable, and it's probably 
+    only going to be implemented on Linux. Application should always try to 
+    use pj_sock_set_qos_type() instead.
+ */
+
+
+/**
+ * High level traffic classification.
+ */
+typedef enum pj_qos_type
+{
+    PJ_QOS_TYPE_BEST_EFFORT,	/**< Best effort traffic (default value).
+				     Any QoS function calls with specifying
+				     this value are effectively no-op	*/
+    PJ_QOS_TYPE_BACKGROUND,	/**< Background traffic.		*/
+    PJ_QOS_TYPE_VIDEO,		/**< Video traffic.			*/
+    PJ_QOS_TYPE_VOICE,		/**< Voice traffic.			*/
+    PJ_QOS_TYPE_CONTROL		/**< Control traffic.			*/
+} pj_qos_type;
+
+/**
+ * Bitmask flag to indicate which QoS layer setting is set in the 
+ * \a flags field of the #pj_qos_params structure. 
+ */
+typedef enum pj_qos_flag
+{
+    PJ_QOS_PARAM_HAS_DSCP = 1,	    /**< DSCP field is set.	    */
+    PJ_QOS_PARAM_HAS_802_1_P = 2,   /**< IEEE 802.1p  field is set  */
+    PJ_QOS_PARAM_HAS_WMM = 4	    /**< WMM  field is set. 	    */
+} pj_qos_flag;
+
+
+/**
+ * Standard WMM priorities.
+ */
+typedef enum pj_qos_wmm_prio
+{
+    PJ_QOS_WMM_PRIO_BULK_EFFORT,	/**< Bulk effort priority   */
+    PJ_QOS_WMM_PRIO_BULK,		/**< Bulk priority.	    */
+    PJ_QOS_WMM_PRIO_VIDEO,		/**< Video priority	    */
+    PJ_QOS_WMM_PRIO_VOICE		/**< Voice priority	    */
+} pj_qos_wmm_prio;
+
+
+/**
+ * QoS parameters to be set or retrieved to/from the socket.
+ */
+typedef struct pj_qos_params
+{
+    pj_uint8_t      flags;    /**< Determines which values to 
+				   set, bitmask of pj_qos_flag	    */
+    pj_uint8_t      dscp_val; /**< DSCP value to set		    */
+    pj_uint8_t      so_prio;  /**< SO_PRIORITY value		    */
+    pj_qos_wmm_prio wmm_prio; /**< WMM priority value		    */
+} pj_qos_params;
+
+
+
+/**
+ * This is the high level and portable API to enable QoS on the specified 
+ * socket, by setting the traffic type to the specified parameter.
+ *
+ * @param sock	    The socket.
+ * @param type	    Traffic type to be set.
+ *
+ * @return	    PJ_SUCCESS if at least Layer 2 or Layer 3 setting is
+ *		    successfully set. If both Layer 2 and Layer 3 settings
+ *		    can't be set, this function will return error.
+ */
+PJ_DECL(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					  pj_qos_type type);
+
+/**
+ * This is the high level and portable API to get the traffic type that has
+ * been set on the socket. On occasions where the Layer 2 or Layer 3 settings
+ * were modified by using low level API, this function may return approximation
+ * of the closest QoS type that matches the settings.
+ *
+ * @param sock	    The socket.
+ * @param p_type    Pointer to receive the traffic type of the socket.
+ *
+ * @return	    PJ_SUCCESS if traffic type for the socket can be obtained
+ *		    or approximated..
+ */
+PJ_DECL(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					  pj_qos_type *p_type);
+
+
+/**
+ * This is a convenience function to apply QoS to the socket, and print error
+ * logging if the operations failed. Both QoS traffic type and the low level
+ * QoS parameters can be applied with this function.
+ *
+ * @param sock		The socket handle.
+ * @param qos_type	QoS traffic type. The QoS traffic type will be applied
+ *			only if the value is not PJ_QOS_TYPE_BEST_EFFORT,
+ * @param qos_params	Optional low-level QoS parameters. This will be 
+ *			applied only if this argument is not NULL and the 
+ *			flags inside the structure is non-zero. Upon return, 
+ *			the flags will indicate which parameters have been 
+ *			applied successfully.
+ * @param log_level	This function will print to log at this level upon
+ *			encountering errors.
+ * @param log_sender	Optional sender name in the log.
+ * @param sock_name	Optional name to help identify the socket in the log.
+ *
+ * @return		PJ_SUCCESS if at least Layer 2 or Layer 3 setting is
+ *			successfully set. If both Layer 2 and Layer 3 settings
+ *			can't be set, this function will return error.
+ *
+ * @see pj_sock_apply_qos2()
+ */
+PJ_DECL(pj_status_t) pj_sock_apply_qos(pj_sock_t sock,
+				       pj_qos_type qos_type,
+				       pj_qos_params *qos_params,
+				       unsigned log_level,
+				       const char *log_sender,
+				       const char *sock_name);
+
+/**
+ * Variant of #pj_sock_apply_qos() where the \a qos_params parameter is
+ * const.
+ *
+ * @see pj_sock_apply_qos()
+ */
+PJ_DECL(pj_status_t) pj_sock_apply_qos2(pj_sock_t sock,
+ 				        pj_qos_type qos_type,
+				        const pj_qos_params *qos_params,
+				        unsigned log_level,
+				        const char *log_sender,
+				        const char *sock_name);
+
+/**
+ * Retrieve the standard mapping of QoS params for the specified traffic
+ * type.
+ *
+ * @param type	    The traffic type from which the QoS parameters
+ *		    are to be retrieved.
+ * @param p_param   Pointer to receive the QoS parameters.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */ 
+PJ_DECL(pj_status_t) pj_qos_get_params(pj_qos_type type, 
+				       pj_qos_params *p_param);
+
+
+/**
+ * Retrieve the traffic type that matches the specified QoS parameters.
+ * If no exact matching is found, this function will return an
+ * approximation of the closest matching traffic type for the specified
+ * QoS parameters.
+ *
+ * @param param	    Structure containing QoS parameters to map into
+ *		    "standard" traffic types.
+ * @param p_type    Pointer to receive the traffic type.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */ 
+PJ_DECL(pj_status_t) pj_qos_get_type(const pj_qos_params *param,
+				     pj_qos_type *p_type);
+
+
+/**
+ * This is a low level API to set QoS parameters to the socket.
+ *
+ * @param sock	    The socket.
+ * @param param	    Structure containing QoS parameters to be applied
+ *		    to the socket. Upon return, the \a flags field
+ *		    of this structure will be set with bitmask value
+ *		    indicating which QoS settings have successfully
+ *		    been applied to the socket.
+ *
+ * @return	    PJ_SUCCESS if at least one field setting has been
+ *		    successfully set. If no setting can't be set, 
+ *		    this function will return error.
+ */ 
+PJ_DECL(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+					    pj_qos_params *param);
+
+/**
+ * This is a low level API to get QoS parameters from the socket.
+ *
+ * @param sock	    The socket.
+ * @param p_param   Pointer to receive the parameters. Upon returning
+ *		    successfully, the \a flags field of this structure
+ *		    will be initialized with the appropriate bitmask
+ *		    to indicate which fields have been successfully
+ *		    retrieved.
+ *
+ * @return	    PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+					    pj_qos_params *p_param);
+
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+#endif	/* __PJ_SOCK_QOS_H__ */
+
diff --git a/pjlib/include/pjlib.h b/pjlib/include/pjlib.h
index fa88510..648c594 100644
--- a/pjlib/include/pjlib.h
+++ b/pjlib/include/pjlib.h
@@ -50,6 +50,7 @@
 #include <pj/rand.h>
 #include <pj/rbtree.h>
 #include <pj/sock.h>
+#include <pj/sock_qos.h>
 #include <pj/sock_select.h>
 #include <pj/string.h>
 #include <pj/timer.h>
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index 6cf24fe..36761bc 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -63,7 +63,7 @@
 #elif defined(PJ_WIN32) && PJ_WIN32
 const pj_uint16_t PJ_SOL_IP	= IPPROTO_IP;
 #else
-const pj_uint16_t PJ_SOL_IP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_IP	= 0;
 #endif /* SOL_IP */
 
 #if defined(SOL_TCP)
@@ -73,7 +73,7 @@
 #elif defined(PJ_WIN32) && PJ_WIN32
 const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;
 #else
-const pj_uint16_t PJ_SOL_TCP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_TCP	= 6;
 #endif /* SOL_TCP */
 
 #ifdef SOL_UDP
@@ -83,7 +83,7 @@
 #elif defined(PJ_WIN32) && PJ_WIN32
 const pj_uint16_t PJ_SOL_UDP	= IPPROTO_UDP;
 #else
-const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_UDP	= 17;
 #endif /* SOL_UDP */
 
 #ifdef SOL_IPV6
@@ -95,7 +95,7 @@
 	const pj_uint16_t PJ_SOL_IPV6	= 41;
 #   endif
 #else
-const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;
+const pj_uint16_t PJ_SOL_IPV6	= 41;
 #endif /* SOL_IPV6 */
 
 /* IP_TOS */
@@ -135,6 +135,12 @@
 const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;
 const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
 const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
+#if defined(SO_PRIORITY)
+const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
+#else
+/* This is from Linux, YMMV */
+const pj_uint16_t PJ_SO_PRIORITY = 12;
+#endif
 
 /* Multicasting is not supported e.g. in PocketPC 2003 SDK */
 #ifdef IP_MULTICAST_IF
diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c
index 0e098c4..64fc9d4 100644
--- a/pjlib/src/pj/sock_common.c
+++ b/pjlib/src/pj/sock_common.c
@@ -1072,6 +1072,11 @@
     return PJ_SO_REUSEADDR;
 }
 
+PJ_DEF(pj_uint16_t) pj_SO_PRIORITY(void)
+{
+    return PJ_SO_PRIORITY;
+}
+
 PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_IF(void)
 {
     return PJ_IP_MULTICAST_IF;
diff --git a/pjlib/src/pj/sock_qos_bsd.c b/pjlib/src/pj/sock_qos_bsd.c
new file mode 100644
index 0000000..32b2828
--- /dev/null
+++ b/pjlib/src/pj/sock_qos_bsd.c
@@ -0,0 +1,130 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/sock_qos.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+
+/* This is the implementation of QoS with BSD socket's setsockopt(),
+ * using IP_TOS and SO_PRIORITY
+ */ 
+#if !defined(PJ_QOS_IMPLEMENTATION) || PJ_QOS_IMPLEMENTATION==PJ_QOS_BSD
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+					   pj_qos_params *param)
+{
+    pj_status_t last_err = PJ_ENOTSUP;
+    pj_status_t status;
+
+    /* No op? */
+    if (!param->flags)
+	return PJ_SUCCESS;
+
+    /* Clear WMM field since we don't support it */
+    param->flags &= ~(PJ_QOS_PARAM_HAS_WMM);
+
+    /* Set TOS/DSCP */
+    if (param->flags & PJ_QOS_PARAM_HAS_DSCP) {
+	int val = param->dscp_val;
+	status = pj_sock_setsockopt(sock, pj_SOL_IP(), pj_IP_TOS(), 
+				    &val, sizeof(val));
+	if (status != PJ_SUCCESS) {
+	    param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP);
+	    last_err = status;
+	}
+    }
+
+    /* Set SO_PRIORITY */
+    if (param->flags & PJ_QOS_PARAM_HAS_802_1_P) {
+	int val = param->so_prio;
+	status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_PRIORITY(),
+				    &val, sizeof(val));
+	if (status != PJ_SUCCESS) {
+	    param->flags &= ~(PJ_QOS_PARAM_HAS_802_1_P);
+	    last_err = status;
+	}
+    }
+
+    return param->flags ? PJ_SUCCESS : last_err;
+}
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					 pj_qos_type type)
+{
+    pj_qos_params param;
+    pj_status_t status;
+
+    status = pj_qos_get_params(type, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    return pj_sock_set_qos_params(sock, &param);
+}
+
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+					   pj_qos_params *p_param)
+{
+    pj_status_t last_err = PJ_ENOTSUP;
+    int val, optlen;
+    pj_status_t status;
+
+    pj_bzero(p_param, sizeof(*p_param));
+
+    /* Get DSCP/TOS value */
+    optlen = sizeof(val);
+    status = pj_sock_getsockopt(sock, pj_SOL_IP(), pj_IP_TOS(), 
+				&val, &optlen);
+    if (status == PJ_SUCCESS) {
+	p_param->flags |= PJ_QOS_PARAM_HAS_DSCP;
+	p_param->dscp_val = (pj_uint8_t)val;
+    } else {
+	last_err = status;
+    }
+
+    /* Get SO_PRIORITY */
+    optlen = sizeof(val);
+    status = pj_sock_getsockopt(sock, pj_SOL_SOCKET(), pj_SO_PRIORITY(),
+				&val, &optlen);
+    if (status == PJ_SUCCESS) {
+	p_param->flags |= PJ_QOS_PARAM_HAS_802_1_P;
+	p_param->so_prio = (pj_uint8_t)val;
+    } else {
+	last_err = status;
+    }
+
+    /* WMM is not supported */
+
+    return p_param->flags ? PJ_SUCCESS : last_err;
+}
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					 pj_qos_type *p_type)
+{
+    pj_qos_params param;
+    pj_status_t status;
+
+    status = pj_sock_get_qos_params(sock, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    return pj_qos_get_type(&param, p_type);
+}
+
+#endif	/* PJ_QOS_IMPLEMENTATION */
diff --git a/pjlib/src/pj/sock_qos_common.c b/pjlib/src/pj/sock_qos_common.c
new file mode 100644
index 0000000..a59b606
--- /dev/null
+++ b/pjlib/src/pj/sock_qos_common.c
@@ -0,0 +1,154 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/sock_qos.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/string.h>
+
+#define THIS_FILE   "sock_qos_common.c"
+#define ALL_FLAGS   (PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_802_1_P | \
+                     PJ_QOS_PARAM_HAS_WMM)
+
+/* "Standard" mapping between traffic type and QoS params */
+static const pj_qos_params qos_map[] = 
+{
+    /* flags	dscp  prio wmm_prio */
+    {ALL_FLAGS, 0x00, 0,    PJ_QOS_WMM_PRIO_BULK_EFFORT},   /* BE */
+    {ALL_FLAGS, 0x08, 2,    PJ_QOS_WMM_PRIO_BULK},	    /* BK */
+    {ALL_FLAGS, 0x28, 5,    PJ_QOS_WMM_PRIO_VIDEO},	    /* VI */
+    {ALL_FLAGS, 0x30, 6,    PJ_QOS_WMM_PRIO_VOICE},	    /* VO */
+    {ALL_FLAGS, 0x38, 7,    PJ_QOS_WMM_PRIO_VOICE}	    /* CO */
+};
+
+
+/* Retrieve the mapping for the specified type */
+PJ_DEF(pj_status_t) pj_qos_get_params(pj_qos_type type, 
+				      pj_qos_params *p_param)
+{
+    PJ_ASSERT_RETURN(type<=PJ_QOS_TYPE_CONTROL && p_param, PJ_EINVAL);
+    pj_memcpy(p_param, &qos_map[type], sizeof(*p_param));
+    return PJ_SUCCESS;
+}
+
+/* Get the matching traffic type */
+PJ_DEF(pj_status_t) pj_qos_get_type( const pj_qos_params *param,
+				     pj_qos_type *p_type)
+{
+    unsigned dscp_type = PJ_QOS_TYPE_BEST_EFFORT,
+	     prio_type = PJ_QOS_TYPE_BEST_EFFORT,
+	     wmm_type = PJ_QOS_TYPE_BEST_EFFORT;
+    unsigned i, count=0;
+
+    PJ_ASSERT_RETURN(param && p_type, PJ_EINVAL);
+
+    if (param->flags & PJ_QOS_PARAM_HAS_DSCP)  {
+	for (i=0; i<=PJ_QOS_TYPE_CONTROL; ++i) {
+	    if (param->dscp_val >= qos_map[i].dscp_val)
+		dscp_type = (pj_qos_type)i;
+	}
+	++count;
+    }
+
+    if (param->flags & PJ_QOS_PARAM_HAS_802_1_P) {
+	for (i=0; i<=PJ_QOS_TYPE_CONTROL; ++i) {
+	    if (param->so_prio >= qos_map[i].so_prio)
+		prio_type = (pj_qos_type)i;
+	}
+	++count;
+    }
+
+    if (param->flags & PJ_QOS_PARAM_HAS_WMM) {
+	for (i=0; i<=PJ_QOS_TYPE_CONTROL; ++i) {
+	    if (param->wmm_prio >= qos_map[i].wmm_prio)
+		wmm_type = (pj_qos_type)i;
+	}
+	++count;
+    }
+
+    if (count)
+	*p_type = (pj_qos_type)((dscp_type + prio_type + wmm_type) / count);
+    else
+	*p_type = PJ_QOS_TYPE_BEST_EFFORT;
+
+    return PJ_SUCCESS;
+}
+
+/* Apply QoS */
+PJ_DEF(pj_status_t) pj_sock_apply_qos( pj_sock_t sock,
+				       pj_qos_type qos_type,
+				       pj_qos_params *qos_params,
+				       unsigned log_level,
+				       const char *log_sender,
+				       const char *sock_name)
+{
+    char fmt[60];
+    pj_status_t qos_type_rc = PJ_SUCCESS,
+		qos_params_rc = PJ_SUCCESS;
+
+    if (!log_sender)
+	log_sender = THIS_FILE;
+    if (!sock_name)
+	sock_name = "socket";
+
+    if (qos_type != PJ_QOS_TYPE_BEST_EFFORT) {
+	qos_type_rc = pj_sock_set_qos_type(sock, qos_type);
+
+	if (qos_type_rc != PJ_SUCCESS) {
+	    pj_ansi_snprintf(fmt, sizeof(fmt),
+			     "Error setting QoS type %d to %s",
+			     qos_type, sock_name);
+	    pj_perror(log_level, log_sender,  qos_type_rc, fmt, 0);
+	}
+    }
+
+    if (qos_params && qos_params->flags) {
+	qos_params_rc = pj_sock_set_qos_params(sock, qos_params);
+	if (qos_params_rc != PJ_SUCCESS) {
+	    pj_ansi_snprintf(fmt, sizeof(fmt),
+			     "Error setting QoS params (flags=%d) to %s",
+			     qos_params->flags, sock_name);
+	    pj_perror(log_level, log_sender,  qos_params_rc, fmt, 0);
+	    if (qos_type_rc != PJ_SUCCESS)
+		return qos_params_rc;
+	}
+    } else if (qos_type_rc != PJ_SUCCESS)
+	return qos_type_rc;
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_sock_apply_qos2( pj_sock_t sock,
+ 				        pj_qos_type qos_type,
+				        const pj_qos_params *qos_params,
+				        unsigned log_level,
+				        const char *log_sender,
+				        const char *sock_name)
+{
+    pj_qos_params qos_params_buf, *qos_params_copy = NULL;
+
+    if (qos_params) {
+	pj_memcpy(&qos_params_buf, qos_params, sizeof(*qos_params));
+	qos_params_copy = &qos_params_buf;
+    }
+
+    return pj_sock_apply_qos(sock, qos_type, qos_params_copy,
+			     log_level, log_sender, sock_name);
+}
diff --git a/pjlib/src/pj/sock_qos_dummy.c b/pjlib/src/pj/sock_qos_dummy.c
new file mode 100644
index 0000000..946b26b
--- /dev/null
+++ b/pjlib/src/pj/sock_qos_dummy.c
@@ -0,0 +1,76 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/sock_qos.h>
+#include <pj/errno.h>
+#include <pj/log.h>
+
+/* Dummy implementation of QoS API. 
+ * (this is controlled by pjlib's config.h)
+ */
+#if defined(PJ_QOS_IMPLEMENTATION) && PJ_QOS_IMPLEMENTATION==PJ_QOS_DUMMY
+
+#define THIS_FILE   "sock_qos_dummy.c"
+
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+					   pj_qos_params *param)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(param);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_set_qos_params() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					 pj_qos_type type)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(type);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_set_qos_type() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+					   pj_qos_params *p_param)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(p_param);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_get_qos_params() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					 pj_qos_type *p_type)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(p_type);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_get_qos_type() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+#endif	/* PJ_QOS_DUMMY */
diff --git a/pjlib/src/pj/sock_qos_symbian.cpp b/pjlib/src/pj/sock_qos_symbian.cpp
new file mode 100644
index 0000000..59912ec
--- /dev/null
+++ b/pjlib/src/pj/sock_qos_symbian.cpp
@@ -0,0 +1,91 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/sock_qos.h>
+#include "os_symbian.h"
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+					   pj_qos_params *param)
+{
+    CPjSocket *pjsock = (CPjSocket*)sock;
+    RSocket & rsock = pjsock->Socket();
+    pj_status_t last_err = PJ_ENOTSUP;
+    
+    /* SO_PRIORITY and WMM are not supported */
+    param->flags &= ~(PJ_QOS_PARAM_HAS_802_1_P | PJ_QOS_PARAM_HAS_WMM);
+    
+    if (param->flags & PJ_QOS_PARAM_HAS_DSCP) {
+	TInt err;
+	
+	err = rsock.SetOpt(KSoIpTOS, KProtocolInetIp,
+		           (param->dscp_val << 2));
+	if (err != KErrNone) {
+	    last_err = PJ_RETURN_OS_ERROR(err);
+	    param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP);
+	}
+    }
+    
+    return param->flags ? PJ_SUCCESS : last_err;
+}
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					 pj_qos_type type)
+{
+    pj_qos_params param;
+    pj_status_t status;
+    
+    status = pj_qos_get_params(type, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+    
+    return pj_sock_set_qos_params(sock, &param);
+}
+
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+					   pj_qos_params *p_param)
+{
+    CPjSocket *pjsock = (CPjSocket*)sock;
+    RSocket & rsock = pjsock->Socket();
+    TInt err, dscp;
+    
+    pj_bzero(p_param, sizeof(*p_param));
+
+    err = rsock.GetOpt(KSoIpTOS, KProtocolInetIp, dscp);
+    if (err == KErrNone) {
+	p_param->flags |= PJ_QOS_PARAM_HAS_DSCP;
+	p_param->dscp_val = (dscp >> 2);
+	return PJ_SUCCESS;
+    } else {
+	return PJ_RETURN_OS_ERROR(err);
+    }
+}
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					 pj_qos_type *p_type)
+{
+    pj_qos_params param;
+    pj_status_t status;
+    
+    status = pj_sock_get_qos_params(sock, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+    
+    return pj_qos_get_type(&param, p_type);
+}
+
diff --git a/pjlib/src/pj/sock_qos_wm.c b/pjlib/src/pj/sock_qos_wm.c
new file mode 100644
index 0000000..ecdf2ed
--- /dev/null
+++ b/pjlib/src/pj/sock_qos_wm.c
@@ -0,0 +1,103 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/sock_qos.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/log.h>
+
+#include <winsock.h>
+
+/* QoS implementation for Windows Mobile 6, must be enabled explicitly
+ * (this is controlled by pjlib's config.h)
+ */
+#if defined(PJ_QOS_IMPLEMENTATION) && PJ_QOS_IMPLEMENTATION==PJ_QOS_WM
+
+#define THIS_FILE   "sock_qos_wm.c"
+
+/* Mapping between our traffic type and WM's DSCP traffic types */
+static const int dscp_map[] = 
+{
+    DSCPBestEffort,
+    DSCPBackground,
+    DSCPVideo,
+    DSCPAudio,
+    DSCPControl
+};
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
+					   pj_qos_params *param)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(param);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_set_qos_params() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
+					 pj_qos_type type)
+{
+    int value;
+
+    PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(dscp_map), PJ_EINVAL);
+
+    value = dscp_map[type];
+    return pj_sock_setsockopt(sock, IPPROTO_IP, IP_DSCP_TRAFFIC_TYPE,
+			      &value, sizeof(value));
+}
+
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
+					   pj_qos_params *p_param)
+{
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(p_param);
+
+    PJ_LOG(4,(THIS_FILE, "pj_sock_get_qos_params() is not implemented "
+			 "for this platform"));
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
+					 pj_qos_type *p_type)
+{
+    pj_status_t status;
+    int value, optlen;
+    unsigned i;
+
+    optlen = sizeof(value);
+    value = 0;
+    status = pj_sock_getsockopt(sock, IPPROTO_IP, IP_DSCP_TRAFFIC_TYPE,
+			        &value, &optlen);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    *p_type = PJ_QOS_TYPE_BEST_EFFORT;
+    for (i=0; i<PJ_ARRAY_SIZE(dscp_map); ++i) {
+	if (value == dscp_map[i]) {
+	    *p_type = (pj_qos_type)i;
+	    break;
+	}
+    }
+
+    return PJ_SUCCESS;
+}
+
+#endif	/* PJ_QOS_IMPLEMENTATION */
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
index 138ee86..b169764 100644
--- a/pjlib/src/pj/sock_symbian.cpp
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -64,6 +64,7 @@
 /* Misc */
 const pj_uint16_t PJ_TCP_NODELAY = 0xFFFF;
 const pj_uint16_t PJ_SO_REUSEADDR = 0xFFFF;
+const pj_uint16_t PJ_SO_PRIORITY = 0xFFFF;
 
 /* ioctl() is also not supported. */
 const pj_uint16_t PJ_SO_TYPE    = 0xFFFF;
diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h
index f265e2c..196f2d5 100644
--- a/pjnath/include/pjnath/config.h
+++ b/pjnath/include/pjnath/config.h
@@ -250,14 +250,14 @@
  * the maximum number of components (PJ_ICE_MAX_COMP) value.
  */
 #ifndef PJ_ICE_COMP_BITS
-#   define PJ_ICE_COMP_BITS			    3
+#   define PJ_ICE_COMP_BITS			    1
 #endif
 
 
 /**
  * Maximum number of ICE components.
  */
-#define PJ_ICE_MAX_COMP		    (2<<PJ_ICE_COMP_BITS)
+#define PJ_ICE_MAX_COMP				    (2<<PJ_ICE_COMP_BITS)
 
 /**
  * Use the priority value according to the ice-draft.
diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h
index c021dde..43a837d 100644
--- a/pjnath/include/pjnath/ice_strans.h
+++ b/pjnath/include/pjnath/ice_strans.h
@@ -271,6 +271,13 @@
      */
     struct {
 	/**
+	 * Optional TURN socket settings. The default values will be
+	 * initialized by #pj_turn_sock_cfg_default(). This contains
+	 * settings such as QoS.
+	 */
+	pj_turn_sock_cfg     cfg;
+
+	/**
 	 * Specify the TURN server domain or hostname or IP address.
 	 * If DNS SRV resolution is required, application must fill
 	 * in this setting with the domain name of the TURN server 
@@ -324,6 +331,34 @@
 
     } turn;
 
+    /**
+     * Component specific settings, which will override the settings in
+     * the STUN and TURN settings above. For example, setting the QoS
+     * parameters here allows the application to have different QoS
+     * traffic type for RTP and RTCP component.
+     */
+    struct {
+	/**
+	 * QoS traffic type to be set on this transport. When application
+	 * wants to apply QoS tagging to the transport, it's preferable to
+	 * set this field rather than \a qos_param fields since this is 
+	 * more portable.
+	 *
+	 * Default value is PJ_QOS_TYPE_BEST_EFFORT.
+	 */
+	pj_qos_type qos_type;
+
+	/**
+	 * Set the low level QoS parameters to the transport. This is a 
+	 * lower level operation than setting the \a qos_type field and
+	 * may not be supported on all platforms.
+	 *
+	 * By default all settings in this structure are disabled.
+	 */
+	pj_qos_params qos_params;
+
+    } comp[PJ_ICE_MAX_COMP];
+
 } pj_ice_strans_cfg;
 
 
diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h
index b196b32..95625c9 100644
--- a/pjnath/include/pjnath/stun_sock.h
+++ b/pjnath/include/pjnath/stun_sock.h
@@ -28,6 +28,7 @@
 #include <pjlib-util/resolver.h>
 #include <pj/ioqueue.h>
 #include <pj/sock.h>
+#include <pj/sock_qos.h>
 
 
 PJ_BEGIN_DECL
@@ -247,6 +248,32 @@
      */
     int ka_interval;
 
+    /**
+     * QoS traffic type to be set on this transport. When application wants
+     * to apply QoS tagging to the transport, it's preferable to set this
+     * field rather than \a qos_param fields since this is more portable.
+     *
+     * Default value is PJ_QOS_TYPE_BEST_EFFORT.
+     */
+    pj_qos_type qos_type;
+
+    /**
+     * Set the low level QoS parameters to the transport. This is a lower
+     * level operation than setting the \a qos_type field and may not be
+     * supported on all platforms.
+     *
+     * By default all settings in this structure are disabled.
+     */
+    pj_qos_params qos_params;
+
+    /**
+     * Specify if STUN socket should ignore any errors when setting the QoS
+     * traffic type/parameters.
+     *
+     * Default: PJ_TRUE
+     */
+    pj_bool_t qos_ignore_error;
+
 } pj_stun_sock_cfg;
 
 
diff --git a/pjnath/include/pjnath/turn_sock.h b/pjnath/include/pjnath/turn_sock.h
index f6776b8..fe03461 100644
--- a/pjnath/include/pjnath/turn_sock.h
+++ b/pjnath/include/pjnath/turn_sock.h
@@ -25,6 +25,7 @@
  * @brief TURN relay using UDP client as transport protocol
  */
 #include <pjnath/turn_session.h>
+#include <pj/sock_qos.h>
 
 
 PJ_BEGIN_DECL
@@ -101,6 +102,48 @@
 
 
 /**
+ * This structure describes options that can be specified when creating
+ * the TURN socket. Application should call #pj_turn_sock_cfg_default()
+ * to initialize this structure with its default values before using it.
+ */
+typedef struct pj_turn_sock_cfg
+{
+    /**
+     * QoS traffic type to be set on this transport. When application wants
+     * to apply QoS tagging to the transport, it's preferable to set this
+     * field rather than \a qos_param fields since this is more portable.
+     *
+     * Default value is PJ_QOS_TYPE_BEST_EFFORT.
+     */
+    pj_qos_type qos_type;
+
+    /**
+     * Set the low level QoS parameters to the transport. This is a lower
+     * level operation than setting the \a qos_type field and may not be
+     * supported on all platforms.
+     *
+     * By default all settings in this structure are not set.
+     */
+    pj_qos_params qos_params;
+
+    /**
+     * Specify if STUN socket should ignore any errors when setting the QoS
+     * traffic type/parameters.
+     *
+     * Default: PJ_TRUE
+     */
+    pj_bool_t qos_ignore_error;
+
+} pj_turn_sock_cfg;
+
+
+/**
+ * Initialize pj_turn_sock_cfg structure with default values.
+ */
+PJ_DECL(void) pj_turn_sock_cfg_default(pj_turn_sock_cfg *cfg);
+
+
+/**
  * Create a TURN transport instance with the specified address family and
  * connection type. Once TURN transport instance is created, application
  * must call pj_turn_sock_alloc() to allocate a relay address in the TURN
@@ -114,7 +157,9 @@
  * @param conn_type	Connection type to the TURN server. Both TCP and
  *			UDP are supported.
  * @param cb		Callback to receive events from the TURN transport.
- * @param options	Option flags, currently this value must be zero.
+ * @param setting	Optional settings to be specified to the transport.
+ *			If this parameter is NULL, default values will be
+ *			used.
  * @param user_data	Arbitrary application data to be associated with
  *			this transport.
  * @param p_turn_sock	Pointer to receive the created instance of the
@@ -127,7 +172,7 @@
 					 int af,
 					 pj_turn_tp_type conn_type,
 					 const pj_turn_sock_cb *cb,
-					 unsigned options,
+					 const pj_turn_sock_cfg *setting,
 					 void *user_data,
 					 pj_turn_sock **p_turn_sock);
 
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index cf79ad9..d702c65 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -211,6 +211,7 @@
     pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
     pj_stun_sock_cfg_default(&cfg->stun.cfg);
     pj_turn_alloc_param_default(&cfg->turn.alloc_param);
+    pj_turn_sock_cfg_default(&cfg->turn.cfg);
 
     pj_ice_sess_options_default(&cfg->opt);
 
@@ -273,6 +274,17 @@
 	stun_sock_cb.on_status = &stun_on_status;
 	stun_sock_cb.on_data_sent = &stun_on_data_sent;
 	
+	/* Override component specific QoS settings, if any */
+	if (ice_st->cfg.comp[comp_id-1].qos_type) {
+	    ice_st->cfg.stun.cfg.qos_type = 
+		ice_st->cfg.comp[comp_id-1].qos_type;
+	}
+	if (ice_st->cfg.comp[comp_id-1].qos_params.flags) {
+	    pj_memcpy(&ice_st->cfg.stun.cfg.qos_params,
+		      &ice_st->cfg.comp[comp_id-1].qos_params,
+		      sizeof(ice_st->cfg.stun.cfg.qos_params));
+	}
+
 	/* Create the STUN transport */
 	status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
 				     ice_st->cfg.af, &stun_sock_cb,
@@ -391,10 +403,22 @@
 	turn_sock_cb.on_rx_data = &turn_on_rx_data;
 	turn_sock_cb.on_state = &turn_on_state;
 
+	/* Override with component specific QoS settings, if any */
+	if (ice_st->cfg.comp[comp_id-1].qos_type) {
+	    ice_st->cfg.turn.cfg.qos_type = 
+		ice_st->cfg.comp[comp_id-1].qos_type;
+	}
+	if (ice_st->cfg.comp[comp_id-1].qos_params.flags) {
+	    pj_memcpy(&ice_st->cfg.turn.cfg.qos_params,
+		      &ice_st->cfg.comp[comp_id-1].qos_params,
+		      sizeof(ice_st->cfg.turn.cfg.qos_params));
+	}
+
+	/* Create the TURN transport */
 	status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af,
 				     ice_st->cfg.turn.conn_type,
-				     &turn_sock_cb, 0, comp, 
-				     &comp->turn_sock);
+				     &turn_sock_cb, &ice_st->cfg.turn.cfg, 
+				     comp, &comp->turn_sock);
 	if (status != PJ_SUCCESS) {
 	    return status;
 	}
@@ -453,7 +477,8 @@
     if (status != PJ_SUCCESS)
 	return status;
 
-    PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st, PJ_EINVAL);
+    PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st &&
+		     comp_cnt <= PJ_ICE_MAX_COMP , PJ_EINVAL);
 
     if (name == NULL)
 	name = "ice%p";
diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c
index a0d5ff2..6bdd77e 100644
--- a/pjnath/src/pjnath/stun_sock.c
+++ b/pjnath/src/pjnath/stun_sock.c
@@ -136,6 +136,8 @@
     cfg->max_pkt_size = PJ_STUN_SOCK_PKT_LEN;
     cfg->async_cnt = 1;
     cfg->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
+    cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT;
+    cfg->qos_ignore_error = PJ_TRUE;
 }
 
 
@@ -200,6 +202,14 @@
     if (status != PJ_SUCCESS)
 	goto on_error;
 
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type,
+				&cfg->qos_params, 2, stun_sock->obj_name,
+				NULL);
+    if (status != PJ_SUCCESS && !cfg->qos_ignore_error)
+	goto on_error;
+
+    /* Bind socket */
     if (pj_sockaddr_has_addr(&cfg->bound_addr)) {
 	status = pj_sock_bind(stun_sock->sock_fd, &cfg->bound_addr,
 			      pj_sockaddr_get_len(&cfg->bound_addr));
@@ -758,10 +768,7 @@
 
     /* Log socket error */
     if (status != PJ_SUCCESS) {
-	char errmsg[PJ_ERR_MSG_SIZE];
-
-	pj_strerror(status, errmsg, sizeof(errmsg));
-	PJ_LOG(2,(stun_sock->obj_name, "recvfrom() error: %s", errmsg));
+	pj_perror(2, stun_sock->obj_name, status, "recvfrom() error", 0);
 	return PJ_TRUE;
     }
 
diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c
index 0c71d5c..287b029 100644
--- a/pjnath/src/pjnath/turn_sock.c
+++ b/pjnath/src/pjnath/turn_sock.c
@@ -46,6 +46,7 @@
 
     pj_turn_alloc_param	 alloc_param;
     pj_stun_config	 cfg;
+    pj_turn_sock_cfg	 setting;
 
     pj_bool_t		 destroy_request;
     pj_timer_entry	 timer;
@@ -92,6 +93,14 @@
 static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e);
 
 
+/* Init config */
+PJ_DEF(void) pj_turn_sock_cfg_default(pj_turn_sock_cfg *cfg)
+{
+    pj_bzero(cfg, sizeof(*cfg));
+    cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT;
+    cfg->qos_ignore_error = PJ_TRUE;
+}
+
 /*
  * Create.
  */
@@ -99,21 +108,26 @@
 					int af,
 					pj_turn_tp_type conn_type,
 					const pj_turn_sock_cb *cb,
-					unsigned options,
+					const pj_turn_sock_cfg *setting,
 					void *user_data,
 					pj_turn_sock **p_turn_sock)
 {
     pj_turn_sock *turn_sock;
     pj_turn_session_cb sess_cb;
+    pj_turn_sock_cfg default_setting;
     pj_pool_t *pool;
     const char *name_tmpl;
     pj_status_t status;
 
     PJ_ASSERT_RETURN(cfg && p_turn_sock, PJ_EINVAL);
     PJ_ASSERT_RETURN(af==pj_AF_INET() || af==pj_AF_INET6(), PJ_EINVAL);
-    PJ_ASSERT_RETURN(options==0, PJ_EINVAL);
     PJ_ASSERT_RETURN(conn_type!=PJ_TURN_TP_TCP || PJ_HAS_TCP, PJ_EINVAL);
 
+    if (!setting) {
+	pj_turn_sock_cfg_default(&default_setting);
+	setting = &default_setting;
+    }
+
     switch (conn_type) {
     case PJ_TURN_TP_UDP:
 	name_tmpl = "udprel%p";
@@ -139,6 +153,9 @@
     /* Copy STUN config (this contains ioqueue, timer heap, etc.) */
     pj_memcpy(&turn_sock->cfg, cfg, sizeof(*cfg));
 
+    /* Copy setting (QoS parameters etc */
+    pj_memcpy(&turn_sock->setting, setting, sizeof(*setting));
+
     /* Set callback */
     if (cb) {
 	pj_memcpy(&turn_sock->cb, cb, sizeof(*cb));
@@ -652,6 +669,16 @@
 	    return;
 	}
 
+        /* Apply QoS, if specified */
+	status = pj_sock_apply_qos2(sock, turn_sock->setting.qos_type,
+				    &turn_sock->setting.qos_params, 
+				    (turn_sock->setting.qos_ignore_error?2:1),
+				    turn_sock->pool->obj_name, NULL);
+	if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) {
+	    pj_turn_sock_destroy(turn_sock);
+	    return;
+	}
+
 	/* Create active socket */
 	pj_bzero(&asock_cb, sizeof(asock_cb));
 	asock_cb.on_data_read = &on_data_read;
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index a4449d8..aa935b5 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -59,6 +59,7 @@
     pjsua_media_config	    media_cfg;
     pj_bool_t		    no_refersub;
     pj_bool_t		    ipv6;
+    pj_bool_t		    enable_qos;
     pj_bool_t		    no_tcp;
     pj_bool_t		    no_udp;
     pj_bool_t		    use_tls;
@@ -207,6 +208,7 @@
 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
     puts  ("  --ipv6              Use IPv6 instead for SIP and media.");
 #endif
+    puts  ("  --set-qos           Enable QoS tagging for SIP and media.");
     puts  ("  --local-port=port   Set TCP/UDP port. This implicitly enables both ");
     puts  ("                      TCP and UDP transports on the specified port, unless");
     puts  ("                      if TCP or UDP is disabled.");
@@ -500,7 +502,7 @@
 	   OPT_TLS_NEG_TIMEOUT, OPT_TLS_SRV_NAME,
 	   OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,
 	   OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_JB_MAX_SIZE,
-	   OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6,
+	   OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS,
 #ifdef _IONBF
 	   OPT_STDOUT_NO_BUF,
 #endif
@@ -616,6 +618,7 @@
 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
 	{ "ipv6",	 0, 0, OPT_IPV6},
 #endif
+	{ "set-qos",	 0, 0, OPT_QOS},
 	{ "use-timer",  0, 0, OPT_TIMER},
 	{ "timer-se",   1, 0, OPT_TIMER_SE},
 	{ "timer-min-se", 1, 0, OPT_TIMER_MIN_SE},
@@ -1327,7 +1330,17 @@
 	    cfg->ipv6 = PJ_TRUE;
 	    break;
 #endif
-
+	case OPT_QOS:
+	    cfg->enable_qos = PJ_TRUE;
+	    /* Set RTP traffic type to Voice */
+	    cfg->rtp_cfg.qos_type = PJ_QOS_TYPE_VOICE;
+	    /* Directly apply DSCP value to SIP traffic. Say lets
+	     * set it to CS3 (DSCP 011000). Note that this will not 
+	     * work on all platforms.
+	     */
+	    cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP;
+	    cfg->udp_cfg.qos_params.dscp_val = 0x18;
+	    break;
 	default:
 	    PJ_LOG(1,(THIS_FILE, 
 		      "Argument \"%s\" is not valid. Use --help to see help",
@@ -1607,6 +1620,9 @@
     if (config->ipv6) {
 	pj_strcat2(&cfg, "--ipv6\n");
     }
+    if (config->enable_qos) {
+	pj_strcat2(&cfg, "--set-qos\n");
+    }
 
     /* UDP Transport. */
     pj_ansi_sprintf(line, "--local-port %d\n", config->udp_cfg.port);
diff --git a/pjsip/include/pjsip/sip_transport_tcp.h b/pjsip/include/pjsip/sip_transport_tcp.h
index c2ef1db..50f8256 100644
--- a/pjsip/include/pjsip/sip_transport_tcp.h
+++ b/pjsip/include/pjsip/sip_transport_tcp.h
@@ -26,6 +26,7 @@
  */
 
 #include <pjsip/sip_transport.h>
+#include <pj/sock_qos.h>
 
 
 /* Only declare the API if PJ_HAS_TCP is true */
@@ -44,6 +45,74 @@
  */
 
 /**
+ * Settings to be specified when creating the TCP transport. Application 
+ * should initialize this structure with its default values by calling 
+ * pjsip_tcp_transport_cfg_default().
+ */
+typedef struct pjsip_tcp_transport_cfg
+{
+    /**
+     * Address family to use. Valid values are pj_AF_INET() and
+     * pj_AF_INET6(). Default is pj_AF_INET().
+     */
+    int			af;
+
+    /**
+     * Optional address to bind the socket to. Default is to bind to 
+     * PJ_INADDR_ANY and to any available port.
+     */
+    pj_sockaddr		bind_addr;
+
+    /**
+     * Optional published address, which is the address to be
+     * advertised as the address of this SIP transport. 
+     * By default the bound address will be used as the published address.
+     */
+    pjsip_host_port	addr_name;
+
+    /**
+     * Number of simultaneous asynchronous accept() operations to be 
+     * supported. It is recommended that the number here corresponds to 
+     * the number of processors in the system (or the number of SIP
+     * worker threads).
+     *
+     * Default: 1
+     */
+    unsigned	       async_cnt;
+
+    /**
+     * QoS traffic type to be set on this transport. When application wants
+     * to apply QoS tagging to the transport, it's preferable to set this
+     * field rather than \a qos_param fields since this is more portable.
+     *
+     * Default is QoS not set.
+     */
+    pj_qos_type		qos_type;
+
+    /**
+     * Set the low level QoS parameters to the transport. This is a lower
+     * level operation than setting the \a qos_type field and may not be
+     * supported on all platforms.
+     *
+     * Default is QoS not set.
+     */
+    pj_qos_params	qos_params;
+
+} pjsip_tcp_transport_cfg;
+
+
+/**
+ * Initialize pjsip_tcp_transport_cfg structure with default values for
+ * the specifed address family.
+ *
+ * @param cfg		The structure to initialize.
+ * @param af		Address family to be used.
+ */
+PJ_DECL(void) pjsip_tcp_transport_cfg_default(pjsip_tcp_transport_cfg *cfg,
+					      int af);
+
+
+/**
  * Register support for SIP TCP transport by creating TCP listener on
  * the specified address and port. This function will create an
  * instance of SIP TCP transport factory and register it to the
@@ -110,6 +179,24 @@
 					        unsigned async_cnt,
 					        pjsip_tpfactory **p_factory);
 
+/**
+ * Another variant of #pjsip_tcp_transport_start().
+ *
+ * @param endpt		The SIP endpoint.
+ * @param cfg		TCP transport settings. Application should initialize
+ *			this setting with #pjsip_tcp_transport_cfg_default().
+ * @param p_factory	Optional pointer to receive the instance of the
+ *			SIP TCP transport factory just created.
+ *
+ * @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_tcp_transport_start3(
+					pjsip_endpoint *endpt,
+					const pjsip_tcp_transport_cfg *cfg,
+					pjsip_tpfactory **p_factory
+					);
 
 
 PJ_END_DECL
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 4727448..356cab7 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1517,6 +1517,24 @@
      */
     pjsip_tls_setting	tls_setting;
 
+    /**
+     * QoS traffic type to be set on this transport. When application wants
+     * to apply QoS tagging to the transport, it's preferable to set this
+     * field rather than \a qos_param fields since this is more portable.
+     *
+     * Default is QoS not set.
+     */
+    pj_qos_type		qos_type;
+
+    /**
+     * Set the low level QoS parameters to the transport. This is a lower
+     * level operation than setting the \a qos_type field and may not be
+     * supported on all platforms.
+     *
+     * Default is QoS not set.
+     */
+    pj_qos_params	qos_params;
+
 } pjsua_transport_config;
 
 
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 1692459..8b89d70 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -57,6 +57,8 @@
     pjsip_endpoint	    *endpt;
     pjsip_tpmgr		    *tpmgr;
     pj_activesock_t	    *asock;
+    pj_qos_type		     qos_type;
+    pj_qos_params	     qos_params;
 };
 
 
@@ -164,6 +166,17 @@
     host_port->port = pj_sockaddr_get_port(addr);
 }
 
+/*
+ * Initialize pjsip_tcp_transport_cfg structure with default values.
+ */
+PJ_DEF(void) pjsip_tcp_transport_cfg_default(pjsip_tcp_transport_cfg *cfg,
+					     int af)
+{
+    pj_bzero(cfg, sizeof(*cfg));
+    cfg->af = af;
+    pj_sockaddr_init(cfg->af, &cfg->bind_addr, NULL, 0);
+    cfg->async_cnt = 1;
+}
 
 
 /****************************************************************************
@@ -174,32 +187,33 @@
  * This is the public API to create, initialize, register, and start the
  * TCP listener.
  */
-PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
-					       const pj_sockaddr_in *local,
-					       const pjsip_host_port *a_name,
-					       unsigned async_cnt,
-					       pjsip_tpfactory **p_factory)
+PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
+					pjsip_endpoint *endpt,
+					const pjsip_tcp_transport_cfg *cfg,
+					pjsip_tpfactory **p_factory
+					)
 {
     pj_pool_t *pool;
     pj_sock_t sock = PJ_INVALID_SOCKET;
     struct tcp_listener *listener;
     pj_activesock_cfg asock_cfg;
     pj_activesock_cb listener_cb;
-    pj_sockaddr_in *listener_addr;
+    pj_sockaddr *listener_addr;
     int addr_len;
     pj_status_t status;
 
     /* Sanity check */
-    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
+    PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);
 
     /* Verify that address given in a_name (if any) is valid */
-    if (a_name && a_name->host.slen) {
-	pj_sockaddr_in tmp;
+    if (cfg->addr_name.host.slen) {
+	pj_sockaddr tmp;
 
-	status = pj_sockaddr_in_init(&tmp, &a_name->host, 
-				     (pj_uint16_t)a_name->port);
-	if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY ||
-	    tmp.sin_addr.s_addr == PJ_INADDR_NONE)
+	status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, 
+				  (pj_uint16_t)cfg->addr_name.port);
+	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
+	    (cfg->af==pj_AF_INET() && 
+	     tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) 
 	{
 	    /* Invalid address */
 	    return PJ_EINVAL;
@@ -217,6 +231,9 @@
     listener->factory.type_name = "tcp";
     listener->factory.flag = 
 	pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
+    listener->qos_type = cfg->qos_type;
+    pj_memcpy(&listener->qos_params, &cfg->qos_params,
+	      sizeof(cfg->qos_params));
 
     pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
 
@@ -226,24 +243,27 @@
 	goto on_error;
 
 
-    /* Create and bind socket */
-    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
+    /* Create socket */
+    status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock);
     if (status != PJ_SUCCESS)
 	goto on_error;
 
-    listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr;
-    if (local) {
-	pj_memcpy(listener_addr, local, sizeof(pj_sockaddr_in));
-    } else {
-	pj_sockaddr_in_init(listener_addr, NULL, 0);
-    }
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 
+				2, listener->factory.obj_name, 
+				"SIP TCP listener socket");
 
-    status = pj_sock_bind(sock, listener_addr, sizeof(pj_sockaddr_in));
+    /* Bind socket */
+    listener_addr = &listener->factory.local_addr;
+    pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
+
+    status = pj_sock_bind(sock, listener_addr, 
+			  pj_sockaddr_get_len(listener_addr));
     if (status != PJ_SUCCESS)
 	goto on_error;
 
     /* Retrieve the bound address */
-    addr_len = sizeof(pj_sockaddr_in);
+    addr_len = pj_sockaddr_get_len(listener_addr);
     status = pj_sock_getsockname(sock, listener_addr, &addr_len);
     if (status != PJ_SUCCESS)
 	goto on_error;
@@ -251,12 +271,12 @@
     /* If published host/IP is specified, then use that address as the
      * listener advertised address.
      */
-    if (a_name && a_name->host.slen) {
+    if (cfg->addr_name.host.slen) {
 	/* Copy the address */
-	listener->factory.addr_name = *a_name;
+	listener->factory.addr_name = cfg->addr_name;
 	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
-		  &a_name->host);
-	listener->factory.addr_name.port = a_name->port;
+		  &cfg->addr_name.host);
+	listener->factory.addr_name.port = cfg->addr_name.port;
 
     } else {
 	/* No published address is given, use the bound address */
@@ -264,24 +284,27 @@
 	/* If the address returns 0.0.0.0, use the default
 	 * interface address as the transport's address.
 	 */
-	if (listener_addr->sin_addr.s_addr == 0) {
+	if (!pj_sockaddr_has_addr(listener_addr)) {
 	    pj_sockaddr hostip;
 
 	    status = pj_gethostip(pj_AF_INET(), &hostip);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
 
-	    listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr;
+	    pj_memcpy(pj_sockaddr_get_addr(listener_addr),
+		      pj_sockaddr_get_addr(&hostip),
+		      pj_sockaddr_get_addr_len(&hostip));
 	}
 
 	/* Save the address name */
 	sockaddr_to_host_port(listener->factory.pool, 
-			      &listener->factory.addr_name, listener_addr);
+			      &listener->factory.addr_name, 
+			      (pj_sockaddr_in*)listener_addr);
     }
 
     /* If port is zero, get the bound port */
     if (listener->factory.addr_name.port == 0) {
-	listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port);
+	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
     }
 
     pj_ansi_snprintf(listener->factory.obj_name, 
@@ -296,9 +319,11 @@
 
 
     /* Create active socket */
-    if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT;
     pj_activesock_cfg_default(&asock_cfg);
-    asock_cfg.async_cnt = async_cnt;
+    if (cfg->async_cnt > MAX_ASYNC_CNT) 
+	asock_cfg.async_cnt = MAX_ASYNC_CNT;
+    else
+	asock_cfg.async_cnt = cfg->async_cnt;
 
     pj_bzero(&listener_cb, sizeof(listener_cb));
     listener_cb.on_accept_complete = &on_accept_complete;
@@ -348,6 +373,35 @@
  * This is the public API to create, initialize, register, and start the
  * TCP listener.
  */
+PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
+					       const pj_sockaddr_in *local,
+					       const pjsip_host_port *a_name,
+					       unsigned async_cnt,
+					       pjsip_tpfactory **p_factory)
+{
+    pjsip_tcp_transport_cfg cfg;
+
+    pjsip_tcp_transport_cfg_default(&cfg, pj_AF_INET());
+
+    if (local)
+	pj_sockaddr_cp(&cfg.bind_addr, local);
+    else
+	pj_sockaddr_init(cfg.af, &cfg.bind_addr, NULL, 0);
+
+    if (a_name)
+	pj_memcpy(&cfg.addr_name, a_name, sizeof(*a_name));
+
+    if (async_cnt)
+	cfg.async_cnt = async_cnt;
+
+    return pjsip_tcp_transport_start3(endpt, &cfg, p_factory);
+}
+
+
+/*
+ * This is the public API to create, initialize, register, and start the
+ * TCP listener.
+ */
 PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
 					       const pj_sockaddr_in *local,
 					       unsigned async_cnt,
@@ -774,6 +828,12 @@
     if (status != PJ_SUCCESS)
 	return status;
 
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(sock, listener->qos_type, 
+				&listener->qos_params, 
+				2, listener->factory.obj_name, 
+				"outgoing SIP TCP socket");
+
     /* Bind to any port */
     status = pj_sock_bind_in(sock, 0, 0);
     if (status != PJ_SUCCESS) {
@@ -878,6 +938,12 @@
 	      pj_sockaddr_print(src_addr, addr, sizeof(addr), 3),
 	      sock));
 
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(sock, listener->qos_type, 
+				&listener->qos_params, 
+				2, listener->factory.obj_name, 
+				"incoming SIP TCP socket");
+
     /* 
      * Incoming connection!
      * Create TCP transport for the new socket.
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 773785e..0e39076 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1526,12 +1526,12 @@
  * address via STUN, depending on config).
  */
 static pj_status_t create_sip_udp_sock(int af,
-				       const pj_str_t *bind_param,
-				       int port,
+				       const pjsua_transport_config *cfg,
 				       pj_sock_t *p_sock,
 				       pj_sockaddr *p_pub_addr)
 {
     char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
+    unsigned port = cfg->port;
     pj_str_t stun_srv;
     pj_sock_t sock;
     pj_sockaddr bind_addr;
@@ -1545,8 +1545,8 @@
     }
 
     /* Initialize bound address */
-    if (bind_param->slen) {
-	status = pj_sockaddr_init(af, &bind_addr, bind_param, 
+    if (cfg->bound_addr.slen) {
+	status = pj_sockaddr_init(af, &bind_addr, &cfg->bound_addr, 
 				  (pj_uint16_t)port);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, 
@@ -1558,12 +1558,19 @@
 	pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
     }
 
+    /* Create socket */
     status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "socket() error", status);
 	return status;
     }
 
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(sock, cfg->qos_type, 
+				&cfg->qos_params, 
+				2, THIS_FILE, "SIP UDP socket");
+
+    /* Bind socket */
     status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "bind() error", status);
@@ -1711,8 +1718,7 @@
 	 * (only when public address is not specified).
 	 */
 	status = create_sip_udp_sock(pjsip_transport_type_get_af(type),
-				     &cfg->bound_addr, cfg->port,
-				     &sock, &pub_addr);
+				     cfg, &sock, &pub_addr);
 	if (status != PJ_SUCCESS)
 	    goto on_return;
 
@@ -1743,9 +1749,10 @@
 	 * Create TCP transport.
 	 */
 	pjsua_transport_config config;
-	pjsip_host_port a_name;
 	pjsip_tpfactory *tcp;
-	pj_sockaddr_in local_addr;
+	pjsip_tcp_transport_cfg tcp_cfg;
+
+	pjsip_tcp_transport_cfg_default(&tcp_cfg, pj_AF_INET());
 
 	/* Supply default config if it's not specified */
 	if (cfg == NULL) {
@@ -1753,14 +1760,14 @@
 	    cfg = &config;
 	}
 
-	/* Init local address */
-	pj_sockaddr_in_init(&local_addr, 0, 0);
-
+	/* Configure bind address */
 	if (cfg->port)
-	    local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
+	    pj_sockaddr_set_port(&tcp_cfg.bind_addr, (pj_uint16_t)cfg->port);
 
 	if (cfg->bound_addr.slen) {
-	    status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
+	    status = pj_sockaddr_set_str_addr(tcp_cfg.af, 
+					      &tcp_cfg.bind_addr,
+					      &cfg->bound_addr);
 	    if (status != PJ_SUCCESS) {
 		pjsua_perror(THIS_FILE, 
 			     "Unable to resolve transport bound address", 
@@ -1769,14 +1776,17 @@
 	    }
 	}
 
-	/* Init published name */
-	pj_bzero(&a_name, sizeof(pjsip_host_port));
+	/* Set published name */
 	if (cfg->public_addr.slen)
-	    a_name.host = cfg->public_addr;
+	    tcp_cfg.addr_name.host = cfg->public_addr;
+
+	/* Copy the QoS settings */
+	tcp_cfg.qos_type = cfg->qos_type;
+	pj_memcpy(&tcp_cfg.qos_params, &cfg->qos_params, 
+		  sizeof(cfg->qos_params));
 
 	/* Create the TCP transport */
-	status = pjsip_tcp_transport_start2(pjsua_var.endpt, &local_addr, 
-					    &a_name, 1, &tcp);
+	status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp);
 
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Error creating SIP TCP listener", 
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index fff917b..06d1277 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -384,13 +384,19 @@
     /* Loop retry to bind RTP and RTCP sockets. */
     for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {
 
-	/* Create and bind RTP socket. */
+	/* Create RTP socket. */
 	status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "socket() error", status);
 	    return status;
 	}
 
+	/* Apply QoS to RTP socket, if specified */
+	status = pj_sock_apply_qos2(sock[0], cfg->qos_type, 
+				    &cfg->qos_params, 
+				    2, THIS_FILE, "RTP socket");
+
+	/* Bind RTP socket */
 	status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr), 
 			       next_rtp_port);
 	if (status != PJ_SUCCESS) {
@@ -399,7 +405,7 @@
 	    continue;
 	}
 
-	/* Create and bind RTCP socket. */
+	/* Create RTCP socket. */
 	status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "socket() error", status);
@@ -407,6 +413,12 @@
 	    return status;
 	}
 
+	/* Apply QoS to RTCP socket, if specified */
+	status = pj_sock_apply_qos2(sock[1], cfg->qos_type, 
+				    &cfg->qos_params, 
+				    2, THIS_FILE, "RTCP socket");
+
+	/* Bind RTCP socket */
 	status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr), 
 			       (pj_uint16_t)(next_rtp_port+1));
 	if (status != PJ_SUCCESS) {
@@ -881,7 +893,7 @@
 }
 
 /* Create ICE media transports (when ice is enabled) */
-static pj_status_t create_ice_media_transports(void)
+static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
 {
     char stunip[PJ_INET6_ADDRSTRLEN];
     pj_ice_strans_cfg ice_cfg;
@@ -915,6 +927,11 @@
     if (pjsua_var.media_cfg.ice_max_host_cands >= 0)
 	ice_cfg.stun.max_host_cands = pjsua_var.media_cfg.ice_max_host_cands;
 
+    /* Copy QoS setting to STUN setting */
+    ice_cfg.stun.cfg.qos_type = cfg->qos_type;
+    pj_memcpy(&ice_cfg.stun.cfg.qos_params, &cfg->qos_params,
+	      sizeof(cfg->qos_params));
+
     /* Configure TURN settings */
     if (pjsua_var.media_cfg.enable_turn) {
 	status = parse_host_port(&pjsua_var.media_cfg.turn_server,
@@ -930,6 +947,11 @@
 	pj_memcpy(&ice_cfg.turn.auth_cred, 
 		  &pjsua_var.media_cfg.turn_auth_cred,
 		  sizeof(ice_cfg.turn.auth_cred));
+
+	/* Copy QoS setting to TURN setting */
+	ice_cfg.turn.cfg.qos_type = cfg->qos_type;
+	pj_memcpy(&ice_cfg.turn.cfg.qos_params, &cfg->qos_params,
+		  sizeof(cfg->qos_params));
     }
 
     /* Create each media transport */
@@ -1025,7 +1047,7 @@
 
     /* Create the transports */
     if (pjsua_var.media_cfg.enable_ice) {
-	status = create_ice_media_transports();
+	status = create_ice_media_transports(&cfg);
     } else {
 	status = create_udp_media_transports(&cfg);
     }