From c84878c894b93a322029625f0d16b00a4e66dcb0 Mon Sep 17 00:00:00 2001 From: Riza Sulistyo Date: Wed, 5 Oct 2016 09:52:39 +0000 Subject: Re #1964: Implement QoS for darwin OS which supports SO_NET_SERVICE_TYPE. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5445 74dad513-b988-da41-8d7b-12977e46ad98 --- aconfigure | 10 +- aconfigure.ac | 10 +- pjlib/build/Makefile | 2 +- pjlib/build/os-darwinos.mak | 2 + pjlib/build/os-linux-kernel.mak | 2 + pjlib/build/os-linux.mak | 2 + pjlib/build/os-rtems.mak | 1 + pjlib/build/os-sunos.mak | 2 + pjlib/build/os-win32.mak | 2 + pjlib/include/pj/compat/socket.h | 3 + pjlib/include/pj/config.h | 3 + pjlib/include/pj/sock_qos.h | 11 +- pjlib/src/pj/sock_qos_common.c | 5 +- pjlib/src/pj/sock_qos_darwin.c | 427 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 pjlib/src/pj/sock_qos_darwin.c diff --git a/aconfigure b/aconfigure index b0a63e08..4aa28a50 100755 --- a/aconfigure +++ b/aconfigure @@ -5824,6 +5824,14 @@ case $target in ac_os_objs="$ac_os_objs os_info_iphone.o" ;; esac + # QoS + case $target in + *darwin*) + ;; + *) + ac_os_objs="$ac_os_objs sock_qos_bsd.o" + ;; + esac # UUID case $target in *android*) @@ -5842,7 +5850,7 @@ esac case $target in *darwin*) - ac_os_objs="$ac_os_objs os_core_darwin.o" + ac_os_objs="$ac_os_objs sock_qos_darwin.o os_core_darwin.o" ;; esac diff --git a/aconfigure.ac b/aconfigure.ac index 357313ff..df9e1ae2 100644 --- a/aconfigure.ac +++ b/aconfigure.ac @@ -462,6 +462,14 @@ case $target in ac_os_objs="$ac_os_objs os_info_iphone.o" ;; esac + # QoS + case $target in + *darwin*) + ;; + *) + ac_os_objs="$ac_os_objs sock_qos_bsd.o" + ;; + esac # UUID case $target in *android*) @@ -480,7 +488,7 @@ esac case $target in *darwin*) - ac_os_objs="$ac_os_objs os_core_darwin.o" + ac_os_objs="$ac_os_objs sock_qos_darwin.o os_core_darwin.o" ;; esac diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile index 1e64950d..dedb2101 100644 --- a/pjlib/build/Makefile +++ b/pjlib/build/Makefile @@ -34,7 +34,7 @@ export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ 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 \ os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \ - rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \ + rbtree.o sock_common.o sock_qos_common.o \ ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \ string.o timer.o types.o export PJLIB_CFLAGS += $(_CFLAGS) diff --git a/pjlib/build/os-darwinos.mak b/pjlib/build/os-darwinos.mak index a0d99e71..931a9bdc 100644 --- a/pjlib/build/os-darwinos.mak +++ b/pjlib/build/os-darwinos.mak @@ -18,6 +18,8 @@ export PJLIB_OBJS += ioqueue_select.o export PJLIB_OBJS += file_access_unistd.o file_io_ansi.o +export PJLIB_OBJS += sock_qos_darwin.o + # # TEST_OBJS are operating system specific object files to be included in # the test application. diff --git a/pjlib/build/os-linux-kernel.mak b/pjlib/build/os-linux-kernel.mak index 28cfbc79..1459f9e2 100644 --- a/pjlib/build/os-linux-kernel.mak +++ b/pjlib/build/os-linux-kernel.mak @@ -21,6 +21,8 @@ export PJLIB_OBJS += compat/sigjmp.o compat/setjmp_i386.o \ export PJLIB_OBJS += ioqueue_epoll.o #export PJLIB_OBJS += ioqueue_select.o +export PJLIB_OBJS += sock_qos_bsd.o + # # TEST_OBJS are operating system specific object files to be included in # the test application. diff --git a/pjlib/build/os-linux.mak b/pjlib/build/os-linux.mak index 78123efd..048b1ab1 100644 --- a/pjlib/build/os-linux.mak +++ b/pjlib/build/os-linux.mak @@ -20,6 +20,8 @@ else export PJLIB_OBJS += ioqueue_select.o endif +export PJLIB_OBJS += sock_qos_bsd.o + # # TEST_OBJS are operating system specific object files to be included in # the test application. diff --git a/pjlib/build/os-rtems.mak b/pjlib/build/os-rtems.mak index 30a81f9b..ebc509f4 100644 --- a/pjlib/build/os-rtems.mak +++ b/pjlib/build/os-rtems.mak @@ -18,6 +18,7 @@ export PJLIB_OBJS += addr_resolv_sock.o guid_simple.o \ export PJLIB_OBJS += ioqueue_select.o export PJLIB_OBJS += file_access_unistd.o file_io_ansi.o +export PJLIB_OBJS += sock_qos_bsd.o # # TEST_OBJS are operating system specific object files to be included in diff --git a/pjlib/build/os-sunos.mak b/pjlib/build/os-sunos.mak index 7aa658da..f3bffaa9 100644 --- a/pjlib/build/os-sunos.mak +++ b/pjlib/build/os-sunos.mak @@ -17,6 +17,8 @@ export PJLIB_OBJS += addr_resolv_sock.o file_access_unistd.o \ export PJLIB_OBJS += ioqueue_select.o #export PJLIB_OBJS += ioqueue_epoll.o +export PJLIB_OBJS += sock_qos_bsd.o + # # TEST_OBJS are operating system specific object files to be included in # the test application. diff --git a/pjlib/build/os-win32.mak b/pjlib/build/os-win32.mak index 5be3c8e5..f0f4006f 100644 --- a/pjlib/build/os-win32.mak +++ b/pjlib/build/os-win32.mak @@ -19,6 +19,8 @@ export PJLIB_OBJS += ioqueue_select.o export PJLIB_OBJS += file_io_win32.o file_access_win32.o #export PJLIB_OBJS += file_io_ansi.o +export PJLIB_OBJS += sock_qos_bsd.o + # # TEST_OBJS are operating system specific object files to be included in # the test application. diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h index 26e47b54..025d141f 100644 --- a/pjlib/include/pj/compat/socket.h +++ b/pjlib/include/pj/compat/socket.h @@ -159,18 +159,21 @@ # define OSERR_ECONNRESET WSAECONNRESET # define OSERR_ENOTCONN WSAENOTCONN # define OSERR_EAFNOSUPPORT WSAEAFNOSUPPORT +# define OSERR_ENOPROTOOPT WSAENOPROTOOPT #elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 # define OSERR_EWOULDBLOCK -1 # define OSERR_EINPROGRESS -1 # define OSERR_ECONNRESET -1 # define OSERR_ENOTCONN -1 # define OSERR_EAFNOSUPPORT -1 +# define OSERR_ENOPROTOOPT -1 #else # define OSERR_EWOULDBLOCK EWOULDBLOCK # define OSERR_EINPROGRESS EINPROGRESS # define OSERR_ECONNRESET ECONNRESET # define OSERR_ENOTCONN ENOTCONN # define OSERR_EAFNOSUPPORT EAFNOSUPPORT +# define OSERR_ENOPROTOOPT ENOPROTOOPT #endif diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index ca55ff30..80ae59d2 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -842,6 +842,9 @@ /** QoS backend for Symbian */ #define PJ_QOS_SYMBIAN 4 +/** QoS backend for Darwin */ +#define PJ_QOS_DARWIN 5 + /** * Force the use of some QoS backend API for some platforms. */ diff --git a/pjlib/include/pj/sock_qos.h b/pjlib/include/pj/sock_qos.h index c23204be..7e8d439a 100644 --- a/pjlib/include/pj/sock_qos.h +++ b/pjlib/include/pj/sock_qos.h @@ -121,10 +121,11 @@ PJ_BEGIN_DECL typedef enum pj_qos_type { PJ_QOS_TYPE_BEST_EFFORT, - PJ_QOS_TYPE_BACKGROUND, + PJ_QOS_TYPE_BACKGROUND, PJ_QOS_TYPE_VIDEO, PJ_QOS_TYPE_VOICE, - PJ_QOS_TYPE_CONTROL + PJ_QOS_TYPE_CONTROL, + PJ_QOS_TYPE_SIGNALLING } pj_qos_type; \endcode @@ -141,6 +142,7 @@ PJ_BEGIN_DECL VIDEO 0x28 VI (Video) 5 VOICE 0x30 VO (Voice) 6 CONTROL 0x38 VO (Voice) 7 + SIGNALLING 0x28 VI (Video) 5 ================================================================= \endcode @@ -235,10 +237,11 @@ 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_BACKGROUND, /**< Background traffic. */ PJ_QOS_TYPE_VIDEO, /**< Video traffic. */ PJ_QOS_TYPE_VOICE, /**< Voice traffic. */ - PJ_QOS_TYPE_CONTROL /**< Control traffic. */ + PJ_QOS_TYPE_CONTROL, /**< Control traffic. */ + PJ_QOS_TYPE_SIGNALLING /**< Signalling traffic. */ } pj_qos_type; /** diff --git a/pjlib/src/pj/sock_qos_common.c b/pjlib/src/pj/sock_qos_common.c index b12d0973..08ba926e 100644 --- a/pjlib/src/pj/sock_qos_common.c +++ b/pjlib/src/pj/sock_qos_common.c @@ -31,10 +31,11 @@ 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, 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 */ + {ALL_FLAGS, 0x38, 7, PJ_QOS_WMM_PRIO_VOICE}, /* CO */ + {ALL_FLAGS, 0x28, 5, PJ_QOS_WMM_PRIO_VIDEO} /* SIG */ }; diff --git a/pjlib/src/pj/sock_qos_darwin.c b/pjlib/src/pj/sock_qos_darwin.c new file mode 100644 index 00000000..eb14a692 --- /dev/null +++ b/pjlib/src/pj/sock_qos_darwin.c @@ -0,0 +1,427 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2011 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 +#include +#include +#include +#include + +/* This is the implementation of QoS with BSD socket's setsockopt(), + * using Darwin-specific SO_NET_SERVICE_TYPE if available, and IP_TOS/ + * IPV6_TCLASS as fallback. + */ +#if !defined(PJ_QOS_IMPLEMENTATION) || PJ_QOS_IMPLEMENTATION==PJ_QOS_IOS + +#include + +#ifdef SO_NET_SERVICE_TYPE +static pj_status_t sock_set_net_service_type(pj_sock_t sock, int val) +{ + pj_status_t status; + + status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), SO_NET_SERVICE_TYPE, + &val, sizeof(val)); + if (status == PJ_STATUS_FROM_OS(OSERR_ENOPROTOOPT)) + status = PJ_ENOTSUP; + + return status; +} +#endif + +static pj_status_t sock_set_net_service_type_type(pj_sock_t sock, + pj_qos_type type) +{ +#ifdef SO_NET_SERVICE_TYPE + int val = NET_SERVICE_TYPE_BE; + + switch (type) { + case PJ_QOS_TYPE_BEST_EFFORT: + val = NET_SERVICE_TYPE_BE; + break; + case PJ_QOS_TYPE_BACKGROUND: + val = NET_SERVICE_TYPE_BK; + break; + case PJ_QOS_TYPE_SIGNALLING: + val = NET_SERVICE_TYPE_SIG; + break; + case PJ_QOS_TYPE_VIDEO: + val = NET_SERVICE_TYPE_VI; + break; + case PJ_QOS_TYPE_VOICE: + case PJ_QOS_TYPE_CONTROL: + default: + val = NET_SERVICE_TYPE_VO; + break; + } + + return sock_set_net_service_type(sock, val); +#else + return PJ_ENOTSUP; +#endif +} + +static pj_status_t sock_set_net_service_type_params(pj_sock_t sock, + pj_qos_params *param) +{ +#ifdef SO_NET_SERVICE_TYPE + pj_status_t status; + int val = -1; + + PJ_ASSERT_RETURN(param, PJ_EINVAL); + + /* + * Sources: + * - IETF draft-szigeti-tsvwg-ieee-802-11e-01 + * - iOS 10 SDK, sys/socket.h + */ + if (val == -1 && param->flags & PJ_QOS_PARAM_HAS_DSCP) { + if (param->dscp_val == 0) /* DF */ + val = NET_SERVICE_TYPE_BE; + else if (param->dscp_val < 0x10) /* CS1, AF11, AF12, AF13 */ + val = NET_SERVICE_TYPE_BK; + else if (param->dscp_val == 0x10) /* CS2 */ + val = NET_SERVICE_TYPE_OAM; + else if (param->dscp_val < 0x18) /* AF21, AF22, AF23 */ + val = NET_SERVICE_TYPE_RD; + else if (param->dscp_val < 0x20) /* CS3, AF31, AF32, AF33 */ + val = NET_SERVICE_TYPE_AV; + else if (param->dscp_val == 0x20) /* CS4 */ + val = NET_SERVICE_TYPE_RD; + else if (param->dscp_val < 0x28) /* AF41, AF42, AF43 */ + val = NET_SERVICE_TYPE_VI; + else if (param->dscp_val == 0x28) /* CS5 */ + val = NET_SERVICE_TYPE_SIG; + else + val = NET_SERVICE_TYPE_VO; /* VOICE-ADMIT, EF, CS6, etc. */ + } + + if (val == -1 && param->flags & PJ_QOS_PARAM_HAS_WMM) { + switch (param->wmm_prio) { + case PJ_QOS_WMM_PRIO_BULK_EFFORT: + val = NET_SERVICE_TYPE_BE; + break; + case PJ_QOS_WMM_PRIO_BULK: + val = NET_SERVICE_TYPE_BK; + break; + case PJ_QOS_WMM_PRIO_VIDEO: + val = NET_SERVICE_TYPE_VI; + break; + case PJ_QOS_WMM_PRIO_VOICE: + val = NET_SERVICE_TYPE_VO; + break; + } + } + + if (val == -1) { + pj_qos_type type; + + status = pj_qos_get_type(param, &type); + + if (status == PJ_SUCCESS) + return sock_set_net_service_type_type(sock, type); + + val = NET_SERVICE_TYPE_BE; + } + + return sock_set_net_service_type(sock, val); +#else + return PJ_ENOTSUP; +#endif +} + +static pj_status_t sock_set_ip_ds(pj_sock_t sock, pj_qos_params *param) +{ + pj_status_t status = PJ_SUCCESS; + + PJ_ASSERT_RETURN(param, PJ_EINVAL); + + if (param->flags & PJ_QOS_PARAM_HAS_DSCP) { + /* We need to know if the socket is IPv4 or IPv6 */ + pj_sockaddr sa; + int salen = sizeof(salen); + + /* Value is dscp_val << 2 */ + int val = (param->dscp_val << 2); + + status = pj_sock_getsockname(sock, &sa, &salen); + if (status != PJ_SUCCESS) + return status; + + if (sa.addr.sa_family == pj_AF_INET()) { + /* In IPv4, the DS field goes in the TOS field */ + status = pj_sock_setsockopt(sock, pj_SOL_IP(), pj_IP_TOS(), + &val, sizeof(val)); + } else if (sa.addr.sa_family == pj_AF_INET6()) { + /* In IPv6, the DS field goes in the Traffic Class field */ + status = pj_sock_setsockopt(sock, pj_SOL_IPV6(), + pj_IPV6_TCLASS(), + &val, sizeof(val)); + } else + status = PJ_EINVAL; + + if (status != PJ_SUCCESS) { + param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP); + } + } + + return status; +} + +PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock, + pj_qos_params *param) +{ + pj_status_t status; + + PJ_ASSERT_RETURN(param, PJ_EINVAL); + + /* No op? */ + if (!param->flags) + return PJ_SUCCESS; + + /* Clear prio field since we don't support it */ + param->flags &= ~(PJ_QOS_PARAM_HAS_SO_PRIO); + + /* Try SO_NET_SERVICE_TYPE */ + status = sock_set_net_service_type_params(sock, param); + if (status == PJ_SUCCESS) + return status; + + if (status != PJ_ENOTSUP) { + /* SO_NET_SERVICE_TYPE sets both DSCP and WMM */ + param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP); + param->flags &= ~(PJ_QOS_PARAM_HAS_WMM); + return status; + } + + /* Fall back to IP_TOS/IPV6_TCLASS */ + return sock_set_ip_ds(sock, param); +} + +PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock, + pj_qos_type type) +{ + pj_status_t status; + pj_qos_params param; + + /* Try SO_NET_SERVICE_TYPE */ + status = sock_set_net_service_type_type(sock, type); + if (status == PJ_SUCCESS || status != PJ_ENOTSUP) + return status; + + /* Fall back to IP_TOS/IPV6_TCLASS */ + status = pj_qos_get_params(type, ¶m); + if (status != PJ_SUCCESS) + return status; + + return sock_set_ip_ds(sock, ¶m); +} + +#ifdef SO_NET_SERVICE_TYPE +static pj_status_t sock_get_net_service_type(pj_sock_t sock, int *p_val) +{ + pj_status_t status; + int optlen = sizeof(*p_val); + + PJ_ASSERT_RETURN(p_val, PJ_EINVAL); + + status = pj_sock_getsockopt(sock, pj_SOL_SOCKET(), SO_NET_SERVICE_TYPE, + p_val, &optlen); + if (status == PJ_STATUS_FROM_OS(OSERR_ENOPROTOOPT)) + status = PJ_ENOTSUP; + + return status; +} +#endif + +static pj_status_t sock_get_net_service_type_type(pj_sock_t sock, + pj_qos_type *p_type) +{ +#ifdef SO_NET_SERVICE_TYPE + pj_status_t status; + int val; + + PJ_ASSERT_RETURN(p_type, PJ_EINVAL); + + status = sock_get_net_service_type(sock, &val); + if (status == PJ_SUCCESS) { + switch (val) { + default: + case NET_SERVICE_TYPE_BE: + *p_type = PJ_QOS_TYPE_BEST_EFFORT; + break; + case NET_SERVICE_TYPE_BK: + *p_type = PJ_QOS_TYPE_BACKGROUND; + break; + case NET_SERVICE_TYPE_SIG: + *p_type = PJ_QOS_TYPE_SIGNALLING; + break; + case NET_SERVICE_TYPE_VI: + case NET_SERVICE_TYPE_RV: + case NET_SERVICE_TYPE_AV: + case NET_SERVICE_TYPE_OAM: + case NET_SERVICE_TYPE_RD: + *p_type = PJ_QOS_TYPE_VIDEO; + break; + case NET_SERVICE_TYPE_VO: + *p_type = PJ_QOS_TYPE_VOICE; + break; + } + } + + return status; +#else + return PJ_ENOTSUP; +#endif +} + +static pj_status_t sock_get_net_service_type_params(pj_sock_t sock, + pj_qos_params *p_param) +{ +#ifdef SO_NET_SERVICE_TYPE + pj_status_t status; + int val; + + PJ_ASSERT_RETURN(p_param, PJ_EINVAL); + + status = sock_get_net_service_type(sock, &val); + if (status == PJ_SUCCESS) { + pj_bzero(p_param, sizeof(*p_param)); + + /* Note: these are just educated guesses, chosen for symmetry with + * sock_set_net_service_type_params: we can't know the actual values + * chosen by the OS, or even if DSCP/WMM are used at all. + * + * The source for mapping DSCP to WMM is: + * - IETF draft-szigeti-tsvwg-ieee-802-11e-01 + */ + switch (val) { + default: + case NET_SERVICE_TYPE_BE: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0; /* DF */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK_EFFORT; /* AC_BE */ + break; + case NET_SERVICE_TYPE_BK: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x08; /* CS1 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK; /* AC_BK */ + break; + case NET_SERVICE_TYPE_SIG: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x28; /* CS5 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */ + break; + case NET_SERVICE_TYPE_VI: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x22; /* AF41 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */ + break; + case NET_SERVICE_TYPE_VO: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x30; /* CS6 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VOICE; /* AC_VO */ + break; + case NET_SERVICE_TYPE_RV: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x22; /* AF41 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */ + break; + case NET_SERVICE_TYPE_AV: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x18; /* CS3 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */ + break; + case NET_SERVICE_TYPE_OAM: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x10; /* CS2 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK_EFFORT; /* AC_BE */ + break; + case NET_SERVICE_TYPE_RD: + p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM; + p_param->dscp_val = 0x20; /* CS4 */ + p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */ + break; + } + } + + return status; +#else + return PJ_ENOTSUP; +#endif +} + +PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock, + pj_qos_params *p_param) +{ + pj_status_t status; + int val, optlen; + pj_sockaddr sa; + int salen = sizeof(salen); + + PJ_ASSERT_RETURN(p_param, PJ_EINVAL); + + pj_bzero(p_param, sizeof(*p_param)); + + /* Try SO_NET_SERVICE_TYPE */ + status = sock_get_net_service_type_params(sock, p_param); + if (status != PJ_ENOTSUP) + return status; + + /* Fall back to IP_TOS/IPV6_TCLASS */ + status = pj_sock_getsockname(sock, &sa, &salen); + if (status != PJ_SUCCESS) + return status; + + optlen = sizeof(val); + if (sa.addr.sa_family == pj_AF_INET()) { + status = pj_sock_getsockopt(sock, pj_SOL_IP(), pj_IP_TOS(), + &val, &optlen); + } else if (sa.addr.sa_family == pj_AF_INET6()) { + status = pj_sock_getsockopt(sock, pj_SOL_IPV6(), pj_IPV6_TCLASS(), + &val, &optlen); + } else + status = PJ_EINVAL; + if (status == PJ_SUCCESS) { + p_param->flags |= PJ_QOS_PARAM_HAS_DSCP; + p_param->dscp_val = (pj_uint8_t)(val >> 2); + } + + return status; +} + +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; + + PJ_ASSERT_RETURN(p_type, PJ_EINVAL); + + status = sock_get_net_service_type_type(sock, p_type); + if (status != PJ_ENOTSUP) + return status; + + status = pj_sock_get_qos_params(sock, ¶m); + if (status != PJ_SUCCESS) + return status; + + return pj_qos_get_type(¶m, p_type); +} + +#endif /* PJ_QOS_IMPLEMENTATION */ -- cgit v1.2.3