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/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>