summaryrefslogtreecommitdiff
path: root/libraries/pjproject-ring
diff options
context:
space:
mode:
authorMario Preksavec <mario@slackware.hr>2018-10-28 01:29:00 +0200
committerWilly Sudiarto Raharjo <willysr@slackbuilds.org>2018-11-03 07:46:59 +0700
commita68fd92ff0bc4473d07eeffea093acf4bf6a8f02 (patch)
tree7bd46461a5095ed7c0f9d7eacf0fff5335da2606 /libraries/pjproject-ring
parent6f07b04688b6a311d651dc1d32f2d8d97845e0aa (diff)
downloadslackbuilds-a68fd92ff0bc4473d07eeffea093acf4bf6a8f02.tar.gz
libraries/pjproject-ring: Removed.
Signed-off-by: Mario Preksavec <mario@slackware.hr>
Diffstat (limited to 'libraries/pjproject-ring')
-rw-r--r--libraries/pjproject-ring/README8
-rw-r--r--libraries/pjproject-ring/patches/add_dtls_transport.patch63
-rw-r--r--libraries/pjproject-ring/patches/android.patch49
-rw-r--r--libraries/pjproject-ring/patches/endianness.patch19
-rw-r--r--libraries/pjproject-ring/patches/fix_base64.patch20
-rw-r--r--libraries/pjproject-ring/patches/fix_ioqueue_ipv6_sendto.patch19
-rw-r--r--libraries/pjproject-ring/patches/fix_turn_fallback.patch53
-rw-r--r--libraries/pjproject-ring/patches/gnutls.patch3295
-rw-r--r--libraries/pjproject-ring/patches/ice_config.patch27
-rw-r--r--libraries/pjproject-ring/patches/intptr_t.patch11
-rw-r--r--libraries/pjproject-ring/patches/ipv6.patch11
-rw-r--r--libraries/pjproject-ring/patches/isblank.patch8
-rw-r--r--libraries/pjproject-ring/patches/multiple_listeners.patch66
-rw-r--r--libraries/pjproject-ring/patches/notestsapps.patch106
-rw-r--r--libraries/pjproject-ring/patches/pj_ice_sess.patch22
-rw-r--r--libraries/pjproject-ring/patches/pj_uwp.patch203
-rw-r--r--libraries/pjproject-ring/patches/pj_uwp_fix_turn_fallback.patch51
-rw-r--r--libraries/pjproject-ring/patches/pj_uwp_gnutls.patch3004
-rw-r--r--libraries/pjproject-ring/patches/pj_uwp_ice_sess.patch25
-rw-r--r--libraries/pjproject-ring/patches/pj_uwp_multiple_listeners.patch64
-rw-r--r--libraries/pjproject-ring/patches/pj_win.patch11
-rw-r--r--libraries/pjproject-ring/pjproject-ring.SlackBuild126
-rw-r--r--libraries/pjproject-ring/pjproject-ring.info10
-rw-r--r--libraries/pjproject-ring/slack-desc19
24 files changed, 0 insertions, 7290 deletions
diff --git a/libraries/pjproject-ring/README b/libraries/pjproject-ring/README
deleted file mode 100644
index 9507d7350d..0000000000
--- a/libraries/pjproject-ring/README
+++ /dev/null
@@ -1,8 +0,0 @@
-PJSIP is a free and open source multimedia communication library written
-in C language implementing standard based protocols such as SIP, SDP,
-RTP, STUN, TURN, and ICE. It combines signaling protocol (SIP) with rich
-multimedia framework and NAT traversal functionality into high level API
-that is portable and suitable for almost any type of systems ranging from
-desktops, embedded systems, to mobile handsets.
-
-This package includes patches from Ring project.
diff --git a/libraries/pjproject-ring/patches/add_dtls_transport.patch b/libraries/pjproject-ring/patches/add_dtls_transport.patch
deleted file mode 100644
index b7f9f296e7..0000000000
--- a/libraries/pjproject-ring/patches/add_dtls_transport.patch
+++ /dev/null
@@ -1,63 +0,0 @@
---- a/pjsip/src/pjsip/sip_transport.c
-+++ b/pjsip/src/pjsip/sip_transport.c
-@@ -183,6 +183,13 @@
- PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE
- },
- {
-+ PJSIP_TRANSPORT_DTLS,
-+ 5061,
-+ {"DTLS", 4},
-+ "DTLS transport",
-+ PJSIP_TRANSPORT_SECURE
-+ },
-+ {
- PJSIP_TRANSPORT_SCTP,
- 5060,
- {"SCTP", 4},
-@@ -224,6 +231,13 @@
- "TLS IPv6 transport",
- PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE
- },
-+ {
-+ PJSIP_TRANSPORT_DTLS6,
-+ 5061,
-+ {"DTLS", 4},
-+ "DTLS IPv6 transport",
-+ PJSIP_TRANSPORT_SECURE
-+ },
- };
-
- static void tp_state_callback(pjsip_transport *tp,
-@@ -249,7 +263,7 @@
- */
- PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag,
- const char *tp_name,
-- int def_port,
-+ int def_port,
- int *p_tp_type)
- {
- unsigned i;
---- a/pjsip/include/pjsip/sip_types.h
-+++ b/pjsip/include/pjsip/sip_types.h
-@@ -73,6 +73,9 @@
- /** TLS. */
- PJSIP_TRANSPORT_TLS,
-
-+ /** DTLS. */
-+ PJSIP_TRANSPORT_DTLS,
-+
- /** SCTP. */
- PJSIP_TRANSPORT_SCTP,
-
-@@ -95,7 +98,10 @@
- PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6,
-
- /** TLS over IPv6 */
-- PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6
-+ PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6,
-+
-+ /** DTLS over IPv6 */
-+ PJSIP_TRANSPORT_DTLS6 = PJSIP_TRANSPORT_DTLS + PJSIP_TRANSPORT_IPV6
-
- } pjsip_transport_type_e;
-
diff --git a/libraries/pjproject-ring/patches/android.patch b/libraries/pjproject-ring/patches/android.patch
deleted file mode 100644
index 01621b9886..0000000000
--- a/libraries/pjproject-ring/patches/android.patch
+++ /dev/null
@@ -1,49 +0,0 @@
---- a/pjlib/include/pj/config.h
-+++ b/pjlib/include/pj/config.h
-@@ -293,6 +293,21 @@
- */
- #include <pj/config_site.h>
-
-+#undef PJ_ANDROID
-+#define PJ_ANDROID 0
-+#define PJ_JNI_HAS_JNI_ONLOAD 0
-+#undef PJ_HAS_FLOATING_POINT
-+#define PJ_HAS_FLOATING_POINT 0
-+#define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 0
-+#define PJMEDIA_AUDIO_DEV_HAS_WMME 0
-+#define PJMEDIA_AUDIO_DEV_HAS_OPENSL 0
-+#define PJMEDIA_AUDIO_DEV_HAS_ANDROID_JNI 0
-+#define PJMEDIA_HAS_L16_CODEC 0
-+#define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY 5
-+#define PJMEDIA_VID_DEV_INFO_FMT_CNT 128
-+#define PJSIP_MAX_TSX_COUNT 31
-+#define PJSIP_MAX_DIALOG_COUNT 31
-+
- /********************************************************************
- * PJLIB Features.
- */
---- a/aconfigure
-+++ b/aconfigure
-@@ -5809,6 +5809,3 @@
- case $target in
-- *android*)
-- ac_os_objs="$ac_os_objs guid_android.o"
-- ;;
- *)
- if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then
---- a/aconfigure.ac
-+++ b/aconfigure.ac
-@@ -457,6 +457,3 @@
- case $target in
-- *android*)
-- ac_os_objs="$ac_os_objs guid_android.o"
-- ;;
- *)
- if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then
---- a/pjlib/src/pj/os_timestamp_posix.c
-+++ b/pjlib/src/pj/os_timestamp_posix.c
-@@ -163,3 +163,3 @@
-
--#elif defined(__ANDROID__)
-+#elif defined(PJ_ANDROID) && PJ_ANDROID
- \ No newline at end of file
diff --git a/libraries/pjproject-ring/patches/endianness.patch b/libraries/pjproject-ring/patches/endianness.patch
deleted file mode 100644
index 84b9499448..0000000000
--- a/libraries/pjproject-ring/patches/endianness.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
-index 10f86fd..4ace1bc 100644
---- a/pjlib/include/pj/config.h
-+++ b/pjlib/include/pj/config.h
-@@ -245,7 +245,13 @@
- # define PJ_M_NAME "armv4"
- # define PJ_HAS_PENTIUM 0
- # if !PJ_IS_LITTLE_ENDIAN && !PJ_IS_BIG_ENDIAN
--# error Endianness must be declared for this processor
-+# if defined(__GNUC__)
-+# include <endian.h>
-+# define PJ_IS_LITTLE_ENDIAN __BYTE_ORDER__ == __LITTLE_ENDIAN__
-+# define PJ_IS_BIG_ENDIAN __BYTE_ORDER__ == __BIG_ENDIAN__
-+# else
-+# error Endianness must be declared for this processor
-+# endif
- # endif
-
- #elif defined (PJ_M_POWERPC) || defined(__powerpc) || defined(__powerpc__) || \
diff --git a/libraries/pjproject-ring/patches/fix_base64.patch b/libraries/pjproject-ring/patches/fix_base64.patch
deleted file mode 100644
index 70bdd5054d..0000000000
--- a/libraries/pjproject-ring/patches/fix_base64.patch
+++ /dev/null
@@ -1,20 +0,0 @@
---- a/pjlib-util/src/pjlib-util/base64.c 2017-05-03 10:29:07.200417026 -0400
-+++ b/pjlib-util/src/pjlib-util/base64.c 2017-05-03 10:28:30.344335390 -0400
-@@ -131,7 +131,7 @@
-
- PJ_ASSERT_RETURN(input && out && out_len, PJ_EINVAL);
-
-- while (buf[len-1] == '=' && len)
-+ while (len && buf[len-1] == '=')
- --len;
-
- PJ_ASSERT_RETURN(*out_len >= PJ_BASE64_TO_BASE256_LEN(len),
-@@ -161,7 +161,7 @@
- out[j++] = (pj_uint8_t)(((c[2] & 0x03)<<6) | (c[3] & 0x3F));
- }
-
-- pj_assert(j < *out_len);
-+ pj_assert(j <= *out_len);
- *out_len = j;
-
- return PJ_SUCCESS;
diff --git a/libraries/pjproject-ring/patches/fix_ioqueue_ipv6_sendto.patch b/libraries/pjproject-ring/patches/fix_ioqueue_ipv6_sendto.patch
deleted file mode 100644
index bc53fd2cb4..0000000000
--- a/libraries/pjproject-ring/patches/fix_ioqueue_ipv6_sendto.patch
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/pjlib/src/pj/ioqueue_common_abs.c 2015-11-05 23:18:46.000000000 -0500
-+++ b/pjlib/src/pj/ioqueue_common_abs.c 2016-10-21 13:49:09.183662433 -0400
-@@ -1048,5 +1048,6 @@
- * Check that address storage can hold the address parameter.
- */
-- PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG);
-+ PJ_ASSERT_RETURN((((pj_sockaddr*)addr)->addr.sa_family == pj_AF_INET() && addrlen <= (int)sizeof(pj_sockaddr_in)) ||
-+ (((pj_sockaddr*)addr)->addr.sa_family == pj_AF_INET6() && addrlen <= (int)sizeof(pj_sockaddr_in6)), PJ_EBUG);
-
- /*
---- a/pjlib/src/pj/ioqueue_common_abs.h 2013-02-21 06:18:36.000000000 -0500
-+++ b/pjlib/src/pj/ioqueue_common_abs.h 2016-10-21 14:04:04.148928591 -0400
-@@ -64,5 +64,5 @@
- pj_ssize_t written;
- unsigned flags;
-- pj_sockaddr_in rmt_addr;
-+ pj_sockaddr rmt_addr;
- int rmt_addrlen;
- };
diff --git a/libraries/pjproject-ring/patches/fix_turn_fallback.patch b/libraries/pjproject-ring/patches/fix_turn_fallback.patch
deleted file mode 100644
index 50229dd01c..0000000000
--- a/libraries/pjproject-ring/patches/fix_turn_fallback.patch
+++ /dev/null
@@ -1,53 +0,0 @@
---- a/pjnath/src/pjnath/turn_session.c 2016-09-19 18:21:09.073614574 -0400
-+++ b/pjnath/src/pjnath/turn_session.c 2016-09-19 18:21:30.648631620 -0400
-@@ -653,3 +653,3 @@
-
-- cnt = PJ_TURN_MAX_DNS_SRV_CNT;
-+ cnt = 1;
- ai = (pj_addrinfo*)
---- a/pjnath/src/pjnath/ice_strans.c 2016-09-19 18:36:04.180104330 -0400
-+++ b/pjnath/src/pjnath/ice_strans.c 2016-09-19 18:37:10.614136809 -0400
-@@ -1304,2 +1304,5 @@
-
-+ if (!comp->turn[n].sock)
-+ continue;
-+
- /* Gather remote addresses for this component */
-@@ -1995,4 +1998,37 @@
- sess_init_update(comp->ice_st);
-
-+ } else if ((old_state == PJ_TURN_STATE_RESOLVING || old_state == PJ_TURN_STATE_ALLOCATING) &&
-+ new_state >= PJ_TURN_STATE_DEALLOCATING)
-+ {
-+ pj_ice_sess_cand *cand = NULL;
-+ unsigned i;
-+
-+ /* DNS resolution has failed! */
-+ ++comp->turn[tp_idx].err_cnt;
-+
-+ /* Unregister ourself from the TURN relay */
-+ pj_turn_sock_set_user_data(turn_sock, NULL);
-+ comp->turn[tp_idx].sock = NULL;
-+
-+ /* Wait until initialization completes */
-+ pj_grp_lock_acquire(comp->ice_st->grp_lock);
-+
-+ /* Find relayed candidate in the component */
-+ for (i=0; i<comp->cand_cnt; ++i) {
-+ if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
-+ comp->cand_list[i].transport_id == data->transport_id)
-+ {
-+ cand = &comp->cand_list[i];
-+ break;
-+ }
-+ }
-+ pj_assert(cand != NULL);
-+
-+ pj_grp_lock_release(comp->ice_st->grp_lock);
-+
-+ cand->status = old_state == PJ_TURN_STATE_RESOLVING ? PJ_ERESOLVE : PJ_EINVALIDOP;
-+
-+ sess_init_update(comp->ice_st);
-+
- } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
- pj_turn_session_info info;
diff --git a/libraries/pjproject-ring/patches/gnutls.patch b/libraries/pjproject-ring/patches/gnutls.patch
deleted file mode 100644
index e8b26657ea..0000000000
--- a/libraries/pjproject-ring/patches/gnutls.patch
+++ /dev/null
@@ -1,3295 +0,0 @@
-Copyright (c) 2014-2017 Savoir-faire Linux Inc.
-
-ssl_sock: add gnutls backend
-
-This backend is mutually exclusive with the OpenSSL one, but completely
-compatible, and conformant to the PJSIP API. Also avoids any license issues
-when linking statically.
-
-The configure script is updated to select either OpenSSL or GnuTLS
-with --enable-ssl[='...'] and a new symbol (PJ_HAS_TLS_SOCK) is introduced
-to identify which backend is in use.
-
-Written by
-Vittorio Giovara <vittorio.giovara@savoirfairelinux.com>
-Philippe Proulx <philippe.proulx@savoirfairelinux.com> and
-Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
-on behalf of Savoir-faire Linux.
-
----
-diff -ru a/aconfigure b/aconfigure
---- a/aconfigure 2017-01-25 06:23:08.000000000 -0500
-+++ b/aconfigure 2017-06-08 13:51:11.146810527 -0400
-@@ -644,6 +644,8 @@
- libcrypto_present
- libssl_present
- openssl_h_present
-+libgnutls_present
-+gnutls_h_present
- ac_ssl_has_aes_gcm
- ac_no_ssl
- ac_openh264_ldflags
-@@ -1482,8 +1484,8 @@
- package and samples location using IPPROOT and
- IPPSAMPLES env var or with --with-ipp and
- --with-ipp-samples options
-- --disable-ssl Exclude SSL support the build (default: autodetect)
--
-+ --enable-ssl=backend Select 'gnutls' or 'openssl' (default) to provide
-+ SSL support (autodetect)
- --disable-opencore-amr Exclude OpenCORE AMR support from the build
- (default: autodetect)
-
-@@ -7787,17 +7789,149 @@
-
- # Check whether --enable-ssl was given.
- if test "${enable_ssl+set}" = set; then :
-- enableval=$enable_ssl;
-- if test "$enable_ssl" = "no"; then
-- ac_no_ssl=1
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
-+ enableval=$enable_ssl; if test "x$enableval" = "xgnutls"; then
-+ ssl_backend="gnutls"
-+ else
-+ ssl_backend="openssl"
-+ fi
-+fi
-+
-+
-+if test "x$enable_ssl" = "xno"; then
-+ ac_no_ssl=1
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
- $as_echo "Checking if SSL support is disabled... yes" >&6; }
-- fi
-+else
-+ if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
-+ CFLAGS="$CFLAGS -I$with_ssl/include"
-+ LDFLAGS="$LDFLAGS -L$with_ssl/lib"
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
-+$as_echo "Using SSL prefix... $with_ssl" >&6; }
-+ fi
-+ if test "x$ssl_backend" = "xgnutls"; then
-+ for ac_prog in $host-pkg-config pkg-config "python pkgconfig.py"
-+do
-+ # Extract the first word of "$ac_prog", so it can be a program name with args.
-+set dummy $ac_prog; ac_word=$2
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-+$as_echo_n "checking for $ac_word... " >&6; }
-+if ${ac_cv_prog_PKG_CONFIG+:} false; then :
-+ $as_echo_n "(cached) " >&6
-+else
-+ if test -n "$PKG_CONFIG"; then
-+ ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
-+else
-+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-+for as_dir in $PATH
-+do
-+ IFS=$as_save_IFS
-+ test -z "$as_dir" && as_dir=.
-+ for ac_exec_ext in '' $ac_executable_extensions; do
-+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-+ ac_cv_prog_PKG_CONFIG="$ac_prog"
-+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-+ break 2
-+ fi
-+done
-+ done
-+IFS=$as_save_IFS
-+
-+fi
-+fi
-+PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
-+if test -n "$PKG_CONFIG"; then
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-+$as_echo "$PKG_CONFIG" >&6; }
-+else
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+fi
-+
-+
-+ test -n "$PKG_CONFIG" && break
-+done
-+test -n "$PKG_CONFIG" || PKG_CONFIG="none"
-+
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for GnuTLS installations.." >&5
-+$as_echo "checking for GnuTLS installations.." >&6; }
-+
-+
-+ ac_fn_c_check_header_mongrel "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default"
-+if test "x$ac_cv_header_gnutls_gnutls_h" = xyes; then :
-+ gnutls_h_present=1
-+fi
-+
-
-+
-+ if test "$PKG_CONFIG" != "none"; then
-+ if $PKG_CONFIG --exists gnutls; then
-+ LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
-+ libgnutls_present=1
-+ else
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_certificate_set_x509_system_trust in -lgnutls" >&5
-+$as_echo_n "checking for gnutls_certificate_set_x509_system_trust in -lgnutls... " >&6; }
-+if ${ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust+:} false; then :
-+ $as_echo_n "(cached) " >&6
-+else
-+ ac_check_lib_save_LIBS=$LIBS
-+LIBS="-lgnutls $LIBS"
-+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h. */
-+
-+/* Override any GCC internal prototype to avoid an error.
-+ Use char because int might match the return type of a GCC
-+ builtin and then its argument prototype would still apply. */
-+#ifdef __cplusplus
-+extern "C"
-+#endif
-+char gnutls_certificate_set_x509_system_trust ();
-+int
-+main ()
-+{
-+return gnutls_certificate_set_x509_system_trust ();
-+ ;
-+ return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_link "$LINENO"; then :
-+ ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=yes
- else
-+ ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=no
-+fi
-+rm -f core conftest.err conftest.$ac_objext \
-+ conftest$ac_exeext conftest.$ac_ext
-+LIBS=$ac_check_lib_save_LIBS
-+fi
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&5
-+$as_echo "$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&6; }
-+if test "x$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" = xyes; then :
-+ libgnutls_present=1 &&
-+ LIBS="$LIBS -lgnutls"
-+fi
-
-+ fi
-+ else
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: *** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&5
-+$as_echo "*** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&6; }
-+ fi
-+
-+ if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: GnuTLS library found, SSL support enabled" >&5
-+$as_echo "GnuTLS library found, SSL support enabled" >&6; }
-+ # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
-+ #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
-+ $as_echo "#define PJ_HAS_SSL_SOCK 1" >>confdefs.h
-+
-+ $as_echo "#define PJ_HAS_TLS_SOCK 1" >>confdefs.h
-+
-+ else
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** No GnuTLS libraries found, disabling SSL support **" >&5
-+$as_echo "** No GnuTLS libraries found, disabling SSL support **" >&6; }
-+ fi
-+ else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OpenSSL installations.." >&5
- $as_echo "checking for OpenSSL installations.." >&6; }
-+
- if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
- CFLAGS="$CFLAGS -I$with_ssl/include"
- LDFLAGS="$LDFLAGS -L$with_ssl/lib"
-@@ -7971,11 +8105,10 @@
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** OpenSSL libraries not found, disabling SSL support **" >&5
- $as_echo "** OpenSSL libraries not found, disabling SSL support **" >&6; }
- fi
--
-+ fi
- fi
-
-
--
- # Check whether --with-opencore-amrnb was given.
- if test "${with_opencore_amrnb+set}" = set; then :
- withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5
-diff -ru a/aconfigure.ac b/aconfigure.ac
---- a/aconfigure.ac 2017-01-25 06:23:08.000000000 -0500
-+++ b/aconfigure.ac 2017-06-08 13:28:17.138135490 -0400
-@@ -1533,18 +1533,59 @@
- dnl # Include SSL support
- AC_SUBST(ac_no_ssl)
- AC_SUBST(ac_ssl_has_aes_gcm,0)
--AC_ARG_ENABLE(ssl,
-- AS_HELP_STRING([--disable-ssl],
-- [Exclude SSL support the build (default: autodetect)])
-- ,
-- [
-- if test "$enable_ssl" = "no"; then
-- [ac_no_ssl=1]
-- AC_MSG_RESULT([Checking if SSL support is disabled... yes])
-- fi
-- ],
-- [
-+AC_ARG_ENABLE([ssl],
-+ AS_HELP_STRING([--enable-ssl[=backend]],
-+ [Select 'gnutls' or 'openssl' (default) to provide SSL support (autodetect)]),
-+ [ if test "x$enableval" = "xgnutls"; then
-+ [ssl_backend="gnutls"]
-+ else
-+ [ssl_backend="openssl"]
-+ fi ])
-+
-+if test "x$enable_ssl" = "xno"; then
-+ [ac_no_ssl=1]
-+ AC_MSG_RESULT([Checking if SSL support is disabled... yes])
-+else
-+ if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
-+ CFLAGS="$CFLAGS -I$with_ssl/include"
-+ LDFLAGS="$LDFLAGS -L$with_ssl/lib"
-+ AC_MSG_RESULT([Using SSL prefix... $with_ssl])
-+ fi
-+ if test "x$ssl_backend" = "xgnutls"; then
-+ AC_CHECK_PROGS(PKG_CONFIG,
-+ $host-pkg-config pkg-config "python pkgconfig.py",
-+ none)
-+ AC_MSG_RESULT([checking for GnuTLS installations..])
-+ AC_SUBST(gnutls_h_present)
-+ AC_SUBST(libgnutls_present)
-+ AC_CHECK_HEADER(gnutls/gnutls.h, [gnutls_h_present=1])
-+
-+ if test "$PKG_CONFIG" != "none"; then
-+ if $PKG_CONFIG --exists gnutls; then
-+ LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
-+ libgnutls_present=1
-+ else
-+ AC_CHECK_LIB(gnutls,
-+ gnutls_certificate_set_x509_system_trust,
-+ [libgnutls_present=1 &&
-+ LIBS="$LIBS -lgnutls"])
-+ fi
-+ else
-+ AC_MSG_RESULT([*** Warning: neither pkg-config nor python is available, disabling gnutls. ***])
-+ fi
-+
-+ if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
-+ AC_MSG_RESULT([GnuTLS library found, SSL support enabled])
-+ # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
-+ #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
-+ AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
-+ AC_DEFINE(PJ_HAS_TLS_SOCK, 1)
-+ else
-+ AC_MSG_RESULT([** No GnuTLS libraries found, disabling SSL support **])
-+ fi
-+ else
- AC_MSG_RESULT([checking for OpenSSL installations..])
-+
- if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
- CFLAGS="$CFLAGS -I$with_ssl/include"
- LDFLAGS="$LDFLAGS -L$with_ssl/lib"
-@@ -1578,7 +1619,8 @@
- else
- AC_MSG_RESULT([** OpenSSL libraries not found, disabling SSL support **])
- fi
-- ])
-+ fi
-+fi
-
- dnl # Obsolete option --with-opencore-amrnb
- AC_ARG_WITH(opencore-amrnb,
-diff -ru a/pjlib/build/Makefile b/pjlib/build/Makefile
---- a/pjlib/build/Makefile 2016-10-05 05:52:39.000000000 -0400
-+++ b/pjlib/build/Makefile 2017-06-08 13:30:20.702138591 -0400
-@@ -35,7 +35,7 @@
- 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 \
-- ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \
-+ ssl_sock_common.o ssl_sock_ossl.o ssl_sock_gtls.o ssl_sock_dump.o \
- string.o timer.o types.o
- export PJLIB_CFLAGS += $(_CFLAGS)
- export PJLIB_CXXFLAGS += $(_CXXFLAGS)
-diff -ru a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in
---- a/pjlib/include/pj/compat/os_auto.h.in 2017-01-24 00:36:50.000000000 -0500
-+++ b/pjlib/include/pj/compat/os_auto.h.in 2017-06-08 13:31:04.976064779 -0400
-@@ -219,6 +219,9 @@
- #ifndef PJ_HAS_SSL_SOCK
- #undef PJ_HAS_SSL_SOCK
- #endif
-+#ifndef PJ_HAS_TLS_SOCK
-+#undef PJ_HAS_TLS_SOCK
-+#endif
-
-
- #endif /* __PJ_COMPAT_OS_AUTO_H__ */
-diff -ru a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
---- a/pjlib/include/pj/config.h 2017-01-25 21:29:59.000000000 -0500
-+++ b/pjlib/include/pj/config.h 2017-06-08 13:34:27.642149351 -0400
-@@ -888,7 +888,7 @@
-
- /**
- * Enable secure socket. For most platforms, this is implemented using
-- * OpenSSL, so this will require OpenSSL to be installed. For Symbian
-+ * OpenSSL or GnuTLS, so this will require OpenSSL or GnuTLS to be installed. For Symbian
- * platform, this is implemented natively using CSecureSocket.
- *
- * Default: 0 (for now)
-@@ -896,6 +896,10 @@
- #ifndef PJ_HAS_SSL_SOCK
- # define PJ_HAS_SSL_SOCK 0
- #endif
-+// When set to 1 secure sockets will use the GnuTLS backend than OpenSSL
-+#ifndef PJ_HAS_TLS_SOCK
-+# define PJ_HAS_TLS_SOCK 0
-+#endif
-
-
- /**
-diff -ru a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h
---- a/pjlib/include/pj/ssl_sock.h 2016-10-27 03:58:01.000000000 -0400
-+++ b/pjlib/include/pj/ssl_sock.h 2017-06-08 13:36:16.448510381 -0400
-@@ -184,6 +184,10 @@
- pj_str_t raw; /**< Raw certificate in PEM format, only
- available for remote certificate. */
-
-+ struct {
-+ unsigned cnt; /**< # of entry */
-+ pj_str_t* cert_raw;
-+ } raw_chain;
- } pj_ssl_cert_info;
-
-
-diff -ru a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c
---- a/pjlib/src/pj/ssl_sock_common.c 2016-10-27 03:58:01.000000000 -0400
-+++ b/pjlib/src/pj/ssl_sock_common.c 2017-06-08 13:37:17.171037628 -0400
-@@ -35,7 +35,12 @@
- param->async_cnt = 1;
- param->concurrency = -1;
- param->whole_data = PJ_TRUE;
-+#if defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 1
-+ // GnuTLS is allowed to send bigger chunks
-+ param->send_buffer_size = 65536;
-+#else
- param->send_buffer_size = 8192;
-+#endif
- #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0
- param->read_buffer_size = 1500;
- #endif
-diff --git a/pjlib/src/pj/ssl_sock_gtls.c b/pjlib/src/pj/ssl_sock_gtls.c
-new file mode 100644
-index 0000000..37bcaba
---- /dev/null
-+++ b/pjlib/src/pj/ssl_sock_gtls.c
-@@ -0,0 +1,2877 @@
-+/* $Id$ */
-+/*
-+ * Copyright (C) 2014-2016 Savoir-faire Linux. (https://www.savoirfairelinux.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/ssl_sock.h>
-+#include <pj/activesock.h>
-+#include <pj/compat/socket.h>
-+#include <pj/assert.h>
-+#include <pj/errno.h>
-+#include <pj/list.h>
-+#include <pj/lock.h>
-+#include <pj/log.h>
-+#include <pj/math.h>
-+#include <pj/os.h>
-+#include <pj/pool.h>
-+#include <pj/string.h>
-+#include <pj/timer.h>
-+#include <pj/file_io.h>
-+
-+#if GNUTLS_VERSION_NUMBER < 0x030306 && !defined(_MSC_VER)
-+#include <dirent.h>
-+#endif
-+
-+#include <errno.h>
-+
-+/* Only build when PJ_HAS_SSL_SOCK and PJ_HAS_TLS_SOCK are enabled */
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK != 0
-+
-+#define THIS_FILE "ssl_sock_gtls.c"
-+
-+/* Workaround for ticket #985 */
-+#define DELAYED_CLOSE_TIMEOUT 200
-+
-+/* Maximum ciphers */
-+#define MAX_CIPHERS 100
-+
-+/* Standard trust locations */
-+#define TRUST_STORE_FILE1 "/etc/ssl/certs/ca-certificates.crt"
-+#define TRUST_STORE_FILE2 "/etc/ssl/certs/ca-bundle.crt"
-+
-+/* Debugging output level for GnuTLS only */
-+#define GNUTLS_LOG_LEVEL 0
-+
-+/* GnuTLS includes */
-+#include <gnutls/gnutls.h>
-+#include <gnutls/x509.h>
-+#include <gnutls/abstract.h>
-+
-+#ifdef _MSC_VER
-+# pragma comment( lib, "libgnutls")
-+#endif
-+
-+
-+/* TLS state enumeration. */
-+enum tls_connection_state {
-+ TLS_STATE_NULL,
-+ TLS_STATE_HANDSHAKING,
-+ TLS_STATE_ESTABLISHED
-+};
-+
-+/* Internal timer types. */
-+enum timer_id {
-+ TIMER_NONE,
-+ TIMER_HANDSHAKE_TIMEOUT,
-+ TIMER_CLOSE
-+};
-+
-+/* Structure of SSL socket read buffer. */
-+typedef struct read_data_t {
-+ void *data;
-+ pj_size_t len;
-+} read_data_t;
-+
-+/*
-+ * Get the offset of pointer to read-buffer of SSL socket from read-buffer
-+ * of active socket. Note that both SSL socket and active socket employ
-+ * different but correlated read-buffers (as much as async_cnt for each),
-+ * and to make it easier/faster to find corresponding SSL socket's read-buffer
-+ * from known active socket's read-buffer, the pointer of corresponding
-+ * SSL socket's read-buffer is stored right after the end of active socket's
-+ * read-buffer.
-+ */
-+#define OFFSET_OF_READ_DATA_PTR(ssock, asock_rbuf) \
-+ (read_data_t**) \
-+ ((pj_int8_t *)(asock_rbuf) + \
-+ ssock->param.read_buffer_size)
-+
-+/* Structure of SSL socket write data. */
-+typedef struct write_data_t {
-+ PJ_DECL_LIST_MEMBER(struct write_data_t);
-+ pj_ioqueue_op_key_t key;
-+ pj_size_t record_len;
-+ pj_ioqueue_op_key_t *app_key;
-+ pj_size_t plain_data_len;
-+ pj_size_t data_len;
-+ unsigned flags;
-+ union {
-+ char content[1];
-+ const char *ptr;
-+ } data;
-+} write_data_t;
-+
-+
-+/* Structure of SSL socket write buffer (circular buffer). */
-+typedef struct send_buf_t {
-+ char *buf;
-+ pj_size_t max_len;
-+ char *start;
-+ pj_size_t len;
-+} send_buf_t;
-+
-+
-+/* Circular buffer object */
-+typedef struct circ_buf_t {
-+ pj_size_t cap; /* maximum number of elements (must be power of 2) */
-+ pj_size_t readp; /* index of oldest element */
-+ pj_size_t writep; /* index at which to write new element */
-+ pj_size_t size; /* number of elements */
-+ pj_uint8_t *buf; /* data buffer */
-+ pj_pool_t *pool; /* where new allocations will take place */
-+} circ_buf_t;
-+
-+
-+/* Secure socket structure definition. */
-+struct pj_ssl_sock_t {
-+ pj_pool_t *pool;
-+ pj_ssl_sock_t *parent;
-+ pj_ssl_sock_param param;
-+ pj_ssl_sock_param newsock_param;
-+ pj_ssl_cert_t *cert;
-+
-+ pj_ssl_cert_info local_cert_info;
-+ pj_ssl_cert_info remote_cert_info;
-+
-+ pj_bool_t is_server;
-+ enum tls_connection_state connection_state;
-+ pj_ioqueue_op_key_t handshake_op_key;
-+ pj_timer_entry timer;
-+ pj_status_t verify_status;
-+
-+ int last_err;
-+
-+ pj_sock_t sock;
-+ pj_activesock_t *asock;
-+
-+ pj_sockaddr local_addr;
-+ pj_sockaddr rem_addr;
-+ int addr_len;
-+
-+ pj_bool_t read_started;
-+ pj_size_t read_size;
-+ pj_uint32_t read_flags;
-+ void **asock_rbuf;
-+ read_data_t *ssock_rbuf;
-+
-+ write_data_t write_pending; /* list of pending writes */
-+ write_data_t write_pending_empty; /* cache for write_pending */
-+ pj_bool_t flushing_write_pend; /* flag of flushing is ongoing */
-+ send_buf_t send_buf;
-+ write_data_t send_pending; /* list of pending write to network */
-+
-+ gnutls_session_t session;
-+ gnutls_certificate_credentials_t xcred;
-+
-+ circ_buf_t circ_buf_input;
-+ pj_lock_t *circ_buf_input_mutex;
-+
-+ circ_buf_t circ_buf_output;
-+ pj_lock_t *circ_buf_output_mutex;
-+
-+ int tls_init_count; /* library initialization counter */
-+};
-+
-+
-+/* Certificate/credential structure definition. */
-+struct pj_ssl_cert_t {
-+ pj_str_t CA_file;
-+ pj_str_t CA_path;
-+ pj_str_t cert_file;
-+ pj_str_t privkey_file;
-+ pj_str_t privkey_pass;
-+};
-+
-+/* GnuTLS available ciphers */
-+static unsigned tls_available_ciphers;
-+
-+/* Array of id/names for available ciphers */
-+static struct tls_ciphers_t {
-+ pj_ssl_cipher id;
-+ const char *name;
-+} tls_ciphers[MAX_CIPHERS];
-+
-+/* Last error reported somehow */
-+static int tls_last_error;
-+
-+
-+/*
-+ *******************************************************************
-+ * Circular buffer functions.
-+ *******************************************************************
-+ */
-+
-+static pj_status_t circ_init(pj_pool_factory *factory,
-+ circ_buf_t *cb, pj_size_t cap)
-+{
-+ cb->cap = cap;
-+ cb->readp = 0;
-+ cb->writep = 0;
-+ cb->size = 0;
-+
-+ /* Initial pool holding the buffer elements */
-+ cb->pool = pj_pool_create(factory, "tls-circ%p", cap, cap, NULL);
-+ if (!cb->pool)
-+ return PJ_ENOMEM;
-+
-+ /* Allocate circular buffer */
-+ cb->buf = pj_pool_alloc(cb->pool, cap);
-+ if (!cb->buf) {
-+ pj_pool_release(cb->pool);
-+ return PJ_ENOMEM;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+static void circ_deinit(circ_buf_t *cb)
-+{
-+ if (cb->pool) {
-+ pj_pool_release(cb->pool);
-+ cb->pool = NULL;
-+ }
-+}
-+
-+static pj_bool_t circ_empty(const circ_buf_t *cb)
-+{
-+ return cb->size == 0;
-+}
-+
-+static pj_size_t circ_size(const circ_buf_t *cb)
-+{
-+ return cb->size;
-+}
-+
-+static pj_size_t circ_avail(const circ_buf_t *cb)
-+{
-+ return cb->cap - cb->size;
-+}
-+
-+static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
-+{
-+ pj_size_t size_after = cb->cap - cb->readp;
-+ pj_size_t tbc = PJ_MIN(size_after, len);
-+ pj_size_t rem = len - tbc;
-+
-+ pj_memcpy(dst, cb->buf + cb->readp, tbc);
-+ pj_memcpy(dst + tbc, cb->buf, rem);
-+
-+ cb->readp += len;
-+ cb->readp &= (cb->cap - 1);
-+
-+ cb->size -= len;
-+}
-+
-+static pj_status_t circ_write(circ_buf_t *cb,
-+ const pj_uint8_t *src, pj_size_t len)
-+{
-+ /* Overflow condition: resize */
-+ if (len > circ_avail(cb)) {
-+ /* Minimum required capacity */
-+ pj_size_t min_cap = len + cb->size;
-+
-+ /* Next 32-bit power of two */
-+ min_cap--;
-+ min_cap |= min_cap >> 1;
-+ min_cap |= min_cap >> 2;
-+ min_cap |= min_cap >> 4;
-+ min_cap |= min_cap >> 8;
-+ min_cap |= min_cap >> 16;
-+ min_cap++;
-+
-+ /* Create a new pool to hold a bigger buffer, using the same factory */
-+ pj_pool_t *pool = pj_pool_create(cb->pool->factory, "tls-circ%p",
-+ min_cap, min_cap, NULL);
-+ if (!pool)
-+ return PJ_ENOMEM;
-+
-+ /* Allocate our new buffer */
-+ pj_uint8_t *buf = pj_pool_alloc(pool, min_cap);
-+ if (!buf) {
-+ pj_pool_release(pool);
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Save old size, which we shall restore after the next read */
-+ pj_size_t old_size = cb->size;
-+
-+ /* Copy old data into beginning of new buffer */
-+ circ_read(cb, buf, cb->size);
-+
-+ /* Restore old size now */
-+ cb->size = old_size;
-+
-+ /* Release the previous pool */
-+ pj_pool_release(cb->pool);
-+
-+ /* Update circular buffer members */
-+ cb->pool = pool;
-+ cb->buf = buf;
-+ cb->readp = 0;
-+ cb->writep = cb->size;
-+ cb->cap = min_cap;
-+ }
-+
-+ pj_size_t size_after = cb->cap - cb->writep;
-+ pj_size_t tbc = PJ_MIN(size_after, len);
-+ pj_size_t rem = len - tbc;
-+
-+ pj_memcpy(cb->buf + cb->writep, src, tbc);
-+ pj_memcpy(cb->buf, src + tbc, rem);
-+
-+ cb->writep += len;
-+ cb->writep &= (cb->cap - 1);
-+
-+ cb->size += len;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ *******************************************************************
-+ * Static/internal functions.
-+ *******************************************************************
-+ */
-+
-+/* Convert from GnuTLS error to pj_status_t. */
-+static pj_status_t tls_status_from_err(pj_ssl_sock_t *ssock, int err)
-+{
-+ pj_status_t status;
-+
-+ switch (err) {
-+ case GNUTLS_E_SUCCESS:
-+ status = PJ_SUCCESS;
-+ break;
-+ case GNUTLS_E_MEMORY_ERROR:
-+ status = PJ_ENOMEM;
-+ break;
-+ case GNUTLS_E_LARGE_PACKET:
-+ status = PJ_ETOOBIG;
-+ break;
-+ case GNUTLS_E_NO_CERTIFICATE_FOUND:
-+ status = PJ_ENOTFOUND;
-+ break;
-+ case GNUTLS_E_SESSION_EOF:
-+ status = PJ_EEOF;
-+ break;
-+ case GNUTLS_E_HANDSHAKE_TOO_LARGE:
-+ status = PJ_ETOOBIG;
-+ break;
-+ case GNUTLS_E_EXPIRED:
-+ status = PJ_EGONE;
-+ break;
-+ case GNUTLS_E_TIMEDOUT:
-+ status = PJ_ETIMEDOUT;
-+ break;
-+ case GNUTLS_E_PREMATURE_TERMINATION:
-+ status = PJ_ECANCELLED;
-+ break;
-+ case GNUTLS_E_INTERNAL_ERROR:
-+ case GNUTLS_E_UNIMPLEMENTED_FEATURE:
-+ status = PJ_EBUG;
-+ break;
-+ case GNUTLS_E_AGAIN:
-+ case GNUTLS_E_INTERRUPTED:
-+ case GNUTLS_E_REHANDSHAKE:
-+ status = PJ_EPENDING;
-+ break;
-+ case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
-+ case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
-+ case GNUTLS_E_RECORD_LIMIT_REACHED:
-+ status = PJ_ETOOMANY;
-+ break;
-+ case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
-+ case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
-+ case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
-+ case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
-+ case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
-+ case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
-+ status = PJ_ENOTSUP;
-+ break;
-+ case GNUTLS_E_INVALID_SESSION:
-+ case GNUTLS_E_INVALID_REQUEST:
-+ case GNUTLS_E_INVALID_PASSWORD:
-+ case GNUTLS_E_ILLEGAL_PARAMETER:
-+ case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
-+ case GNUTLS_E_UNEXPECTED_PACKET:
-+ case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
-+ case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
-+ case GNUTLS_E_UNWANTED_ALGORITHM:
-+ case GNUTLS_E_USER_ERROR:
-+ status = PJ_EINVAL;
-+ break;
-+ default:
-+ status = PJ_EUNKNOWN;
-+ break;
-+ }
-+
-+ /* Not thread safe */
-+ tls_last_error = err;
-+ if (ssock)
-+ ssock->last_err = err;
-+ return status;
-+}
-+
-+
-+/* Get error string from GnuTLS using tls_last_error */
-+static pj_str_t tls_strerror(pj_status_t status,
-+ char *buf, pj_size_t bufsize)
-+{
-+ pj_str_t errstr;
-+ const char *tmp = gnutls_strerror(tls_last_error);
-+
-+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
-+ if (tmp) {
-+ pj_ansi_strncpy(buf, tmp, bufsize);
-+ errstr = pj_str(buf);
-+ return errstr;
-+ }
-+#endif /* PJ_HAS_ERROR_STRING */
-+
-+ errstr.ptr = buf;
-+ errstr.slen = pj_ansi_snprintf(buf, bufsize, "GnuTLS error %d: %s",
-+ tls_last_error, tmp);
-+ if (errstr.slen < 1 || errstr.slen >= (int) bufsize)
-+ errstr.slen = bufsize - 1;
-+
-+ return errstr;
-+}
-+
-+
-+/* Initialize GnuTLS. */
-+static pj_status_t tls_init(void)
-+{
-+ /* Register error subsystem */
-+ pj_status_t status = pj_register_strerror(PJ_ERRNO_START_USER +
-+ PJ_ERRNO_SPACE_SIZE * 6,
-+ PJ_ERRNO_SPACE_SIZE,
-+ &tls_strerror);
-+ pj_assert(status == PJ_SUCCESS);
-+
-+ /* Init GnuTLS library */
-+ int ret = gnutls_global_init();
-+ if (ret < 0)
-+ return tls_status_from_err(NULL, ret);
-+
-+ /* Init available ciphers */
-+ if (!tls_available_ciphers) {
-+ unsigned int i;
-+
-+ for (i = 0; ; i++) {
-+ unsigned char id[2];
-+ const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
-+ NULL, NULL, NULL, NULL);
-+ tls_ciphers[i].id = 0;
-+ /* usually the array size is bigger than the number of available
-+ * ciphers anyway, so by checking here we can exit the loop as soon
-+ * as either all ciphers have been added or the array is full */
-+ if (suite && i < PJ_ARRAY_SIZE(tls_ciphers)) {
-+ tls_ciphers[i].id = (pj_ssl_cipher)
-+ (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ tls_ciphers[i].name = suite;
-+ } else
-+ break;
-+ }
-+
-+ tls_available_ciphers = i;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Shutdown GnuTLS */
-+static void tls_deinit(void)
-+{
-+ gnutls_global_deinit();
-+}
-+
-+
-+/* Callback invoked every time a certificate has to be validated. */
-+static int tls_cert_verify_cb(gnutls_session_t session)
-+{
-+ pj_ssl_sock_t *ssock;
-+ unsigned int status;
-+ int ret;
-+
-+ /* Get SSL socket instance */
-+ ssock = (pj_ssl_sock_t *)gnutls_session_get_ptr(session);
-+ pj_assert(ssock);
-+
-+ /* Support only x509 format */
-+ ret = gnutls_certificate_type_get(session) != GNUTLS_CRT_X509;
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ /* Store verification status */
-+ ret = gnutls_certificate_verify_peers2(session, &status);
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+ if (ssock->param.verify_peer) {
-+ if (status & GNUTLS_CERT_INVALID) {
-+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-+ ssock->verify_status |= PJ_SSL_CERT_EISSUER_NOT_FOUND;
-+ else if (status & GNUTLS_CERT_EXPIRED ||
-+ status & GNUTLS_CERT_NOT_ACTIVATED)
-+ ssock->verify_status |= PJ_SSL_CERT_EVALIDITY_PERIOD;
-+ else if (status & GNUTLS_CERT_SIGNER_NOT_CA ||
-+ status & GNUTLS_CERT_INSECURE_ALGORITHM)
-+ ssock->verify_status |= PJ_SSL_CERT_EUNTRUSTED;
-+ else if (status & GNUTLS_CERT_UNEXPECTED_OWNER ||
-+ status & GNUTLS_CERT_MISMATCH)
-+ ssock->verify_status |= PJ_SSL_CERT_EISSUER_MISMATCH;
-+ else if (status & GNUTLS_CERT_REVOKED)
-+ ssock->verify_status |= PJ_SSL_CERT_EREVOKED;
-+ else
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ /* When verification is not requested just return ok here, however
-+ * applications can still get the verification status. */
-+ gnutls_x509_crt_t cert;
-+ unsigned int cert_list_size;
-+ const gnutls_datum_t *cert_list;
-+ int ret;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto out;
-+
-+ cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
-+ if (cert_list == NULL) {
-+ ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
-+ goto out;
-+ }
-+
-+ /* TODO: verify whole chain perhaps? */
-+ ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, &cert_list[0],
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
-+ goto out;
-+ }
-+ ret = gnutls_x509_crt_check_hostname(cert, ssock->param.server_name.ptr);
-+ if (ret < 0)
-+ goto out;
-+
-+ gnutls_x509_crt_deinit(cert);
-+
-+ /* notify GnuTLS to continue handshake normally */
-+ return GNUTLS_E_SUCCESS;
-+
-+out:
-+ tls_last_error = ret;
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ return GNUTLS_E_SUCCESS;
-+}
-+
-+
-+/* gnutls_handshake() and gnutls_record_send() will call this function to
-+ * send/write (encrypted) data */
-+static ssize_t tls_data_push(gnutls_transport_ptr_t ptr,
-+ const void *data, size_t len)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ if (circ_write(&ssock->circ_buf_output, data, len) != PJ_SUCCESS) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ gnutls_transport_set_errno(ssock->session, ENOMEM);
-+ return -1;
-+ }
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return len;
-+}
-+
-+
-+/* gnutls_handshake() and gnutls_record_recv() will call this function to
-+ * receive/read (encrypted) data */
-+static ssize_t tls_data_pull(gnutls_transport_ptr_t ptr,
-+ void *data, pj_size_t len)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
-+
-+ pj_lock_acquire(ssock->circ_buf_input_mutex);
-+
-+ if (circ_empty(&ssock->circ_buf_input)) {
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+
-+ /* Data buffers not yet filled */
-+ gnutls_transport_set_errno(ssock->session, EAGAIN);
-+ return -1;
-+ }
-+
-+ pj_size_t circ_buf_size = circ_size(&ssock->circ_buf_input);
-+ pj_size_t read_size = PJ_MIN(circ_buf_size, len);
-+
-+ circ_read(&ssock->circ_buf_input, data, read_size);
-+
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+
-+ return read_size;
-+}
-+
-+
-+/* Append a string to the priority string, only once. */
-+static pj_status_t tls_str_append_once(pj_str_t *dst, pj_str_t *src)
-+{
-+ if (pj_strstr(dst, src) == NULL) {
-+ /* Check buffer size */
-+ if (dst->slen + src->slen + 3 > 1024)
-+ return PJ_ETOOMANY;
-+
-+ pj_strcat2(dst, ":+");
-+ pj_strcat(dst, src);
-+ }
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Generate priority string with user preference order. */
-+static pj_status_t tls_priorities_set(pj_ssl_sock_t *ssock)
-+{
-+ char buf[1024];
-+ char priority_buf[256];
-+ pj_str_t cipher_list;
-+ pj_str_t compression = pj_str("COMP-NULL");
-+ pj_str_t server = pj_str(":%SERVER_PRECEDENCE");
-+ int i, j, ret;
-+ pj_str_t priority;
-+ const char *err;
-+
-+ pj_strset(&cipher_list, buf, 0);
-+ pj_strset(&priority, priority_buf, 0);
-+
-+ /* For each level, enable only the requested protocol */
-+ pj_strcat2(&priority, "NORMAL:");
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_2) {
-+ pj_strcat2(&priority, "+VERS-TLS1.2:");
-+ }
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_1) {
-+ pj_strcat2(&priority, "+VERS-TLS1.1:");
-+ }
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1) {
-+ pj_strcat2(&priority, "+VERS-TLS1.0:");
-+ }
-+ pj_strcat2(&priority, "-VERS-SSL3.0:");
-+ pj_strcat2(&priority, "%LATEST_RECORD_VERSION");
-+
-+ pj_strcat(&cipher_list, &priority);
-+ for (i = 0; i < ssock->param.ciphers_num; i++) {
-+ for (j = 0; ; j++) {
-+ pj_ssl_cipher c;
-+ const char *suite;
-+ unsigned char id[2];
-+ gnutls_protocol_t proto;
-+ gnutls_kx_algorithm_t kx;
-+ gnutls_mac_algorithm_t mac;
-+ gnutls_cipher_algorithm_t algo;
-+
-+ suite = gnutls_cipher_suite_info(j, (unsigned char *)id,
-+ &kx, &algo, &mac, &proto);
-+ if (!suite)
-+ break;
-+
-+ c = (pj_ssl_cipher) (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ if (ssock->param.ciphers[i] == c) {
-+ char temp[256];
-+ pj_str_t cipher_entry;
-+
-+ /* Protocol version */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, "VERS-");
-+ pj_strcat2(&cipher_entry, gnutls_protocol_get_name(proto));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Cipher */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_cipher_get_name(algo));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Mac */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_mac_get_name(mac));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Key exchange */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_kx_get_name(kx));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Compression is always disabled */
-+ /* Signature is level-default */
-+ break;
-+ }
-+ }
-+ }
-+
-+ /* Disable compression, it's a TLS-only extension after all */
-+ tls_str_append_once(&cipher_list, &compression);
-+
-+ /* Server will be the one deciding which crypto to use */
-+ if (ssock->is_server) {
-+ if (cipher_list.slen + server.slen + 1 > sizeof(buf))
-+ return PJ_ETOOMANY;
-+ else
-+ pj_strcat(&cipher_list, &server);
-+ }
-+
-+ /* End the string and print it */
-+ cipher_list.ptr[cipher_list.slen] = '\0';
-+ PJ_LOG(5, (ssock->pool->obj_name, "Priority string: %s", cipher_list.ptr));
-+
-+ /* Set our priority string */
-+ ret = gnutls_priority_set_direct(ssock->session,
-+ cipher_list.ptr, &err);
-+ if (ret < 0) {
-+ tls_last_error = GNUTLS_E_INVALID_REQUEST;
-+ return PJ_EINVAL;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Load root CA file or load the installed ones. */
-+static pj_status_t tls_trust_set(pj_ssl_sock_t *ssock)
-+{
-+ int ntrusts = 0;
-+ int err;
-+
-+ err = gnutls_certificate_set_x509_system_trust(ssock->xcred);
-+ if (err > 0)
-+ ntrusts += err;
-+ err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ TRUST_STORE_FILE1,
-+ GNUTLS_X509_FMT_PEM);
-+ if (err > 0)
-+ ntrusts += err;
-+
-+ err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ TRUST_STORE_FILE2,
-+ GNUTLS_X509_FMT_PEM);
-+ if (err > 0)
-+ ntrusts += err;
-+
-+ if (ntrusts > 0)
-+ return PJ_SUCCESS;
-+ else if (!ntrusts)
-+ return PJ_ENOTFOUND;
-+ else
-+ return PJ_EINVAL;
-+}
-+
-+#if GNUTLS_VERSION_NUMBER < 0x030306
-+
-+#ifdef _POSIX_PATH_MAX
-+# define GNUTLS_PATH_MAX _POSIX_PATH_MAX
-+#else
-+# define GNUTLS_PATH_MAX 256
-+#endif
-+
-+static
-+int gnutls_certificate_set_x509_trust_dir(gnutls_certificate_credentials_t cred, const char *dirname, unsigned type)
-+{
-+ DIR *dirp;
-+ struct dirent *d;
-+ int ret;
-+ int r = 0;
-+ char path[GNUTLS_PATH_MAX];
-+#ifndef _WIN32
-+ struct dirent e;
-+#endif
-+
-+ dirp = opendir(dirname);
-+ if (dirp != NULL) {
-+ do {
-+#ifdef _WIN32
-+ d = readdir(dirp);
-+ if (d != NULL) {
-+#else
-+ ret = readdir_r(dirp, &e, &d);
-+ if (ret == 0 && d != NULL
-+#ifdef _DIRENT_HAVE_D_TYPE
-+ && (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
-+#endif
-+ ) {
-+#endif
-+ snprintf(path, sizeof(path), "%s/%s",
-+ dirname, d->d_name);
-+
-+ ret = gnutls_certificate_set_x509_trust_file(cred, path, type);
-+ if (ret >= 0)
-+ r += ret;
-+ }
-+ }
-+ while (d != NULL);
-+ closedir(dirp);
-+ }
-+
-+ return r;
-+}
-+
-+#endif
-+
-+/* Create and initialize new GnuTLS context and instance */
-+static pj_status_t tls_open(pj_ssl_sock_t *ssock)
-+{
-+ pj_ssl_cert_t *cert;
-+ pj_status_t status;
-+ int ret;
-+
-+ pj_assert(ssock);
-+
-+ cert = ssock->cert;
-+
-+ /* Even if reopening is harmless, having one instance only simplifies
-+ * deallocating it later on */
-+ if (!ssock->tls_init_count) {
-+ ssock->tls_init_count++;
-+ ret = tls_init();
-+ if (ret < 0)
-+ return ret;
-+ } else
-+ return PJ_SUCCESS;
-+
-+ /* Start this socket session */
-+ ret = gnutls_init(&ssock->session, ssock->is_server ? GNUTLS_SERVER
-+ : GNUTLS_CLIENT);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Set the ssock object to be retrieved by transport (send/recv) and by
-+ * user data from this session */
-+ gnutls_transport_set_ptr(ssock->session,
-+ (gnutls_transport_ptr_t) (uintptr_t) ssock);
-+ gnutls_session_set_ptr(ssock->session,
-+ (gnutls_transport_ptr_t) (uintptr_t) ssock);
-+
-+ /* Initialize input circular buffer */
-+ status = circ_init(ssock->pool->factory, &ssock->circ_buf_input, 512);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Initialize output circular buffer */
-+ status = circ_init(ssock->pool->factory, &ssock->circ_buf_output, 512);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Set the callback that allows GnuTLS to PUSH and PULL data
-+ * TO and FROM the transport layer */
-+ gnutls_transport_set_push_function(ssock->session, tls_data_push);
-+ gnutls_transport_set_pull_function(ssock->session, tls_data_pull);
-+
-+ /* Determine which cipher suite to support */
-+ status = tls_priorities_set(ssock);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Allocate credentials for handshaking and transmission */
-+ ret = gnutls_certificate_allocate_credentials(&ssock->xcred);
-+ if (ret < 0)
-+ goto out;
-+ gnutls_certificate_set_verify_function(ssock->xcred, tls_cert_verify_cb);
-+
-+ /* Load system trust file(s) */
-+ status = tls_trust_set(ssock);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Load user-provided CA, certificate and key if available */
-+ if (cert) {
-+ /* Load CA if one is specified. */
-+ if (cert->CA_file.slen) {
-+ ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ cert->CA_file.ptr,
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ cert->CA_file.ptr,
-+ GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto out;
-+ }
-+ if (cert->CA_path.slen) {
-+ ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
-+ cert->CA_path.ptr,
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
-+ cert->CA_path.ptr,
-+ GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto out;
-+ }
-+
-+ /* Load certificate, key and pass if one is specified */
-+ if (cert->cert_file.slen && cert->privkey_file.slen) {
-+ const char *prikey_file = cert->privkey_file.ptr;
-+ const char *prikey_pass = cert->privkey_pass.slen
-+ ? cert->privkey_pass.ptr
-+ : NULL;
-+ ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
-+ cert->cert_file.ptr,
-+ prikey_file,
-+ GNUTLS_X509_FMT_PEM,
-+ prikey_pass,
-+ 0);
-+ if (ret != GNUTLS_E_SUCCESS)
-+ ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
-+ cert->cert_file.ptr,
-+ prikey_file,
-+ GNUTLS_X509_FMT_DER,
-+ prikey_pass,
-+ 0);
-+ if (ret < 0)
-+ goto out;
-+ }
-+ }
-+
-+ /* Require client certificate if asked */
-+ if (ssock->is_server && ssock->param.require_client_cert)
-+ gnutls_certificate_server_set_request(ssock->session,
-+ GNUTLS_CERT_REQUIRE);
-+
-+ /* Finally set credentials for this session */
-+ ret = gnutls_credentials_set(ssock->session,
-+ GNUTLS_CRD_CERTIFICATE, ssock->xcred);
-+ if (ret < 0)
-+ goto out;
-+
-+ ret = GNUTLS_E_SUCCESS;
-+out:
-+ return tls_status_from_err(ssock, ret);
-+}
-+
-+
-+/* Destroy GnuTLS credentials and session. */
-+static void tls_close(pj_ssl_sock_t *ssock)
-+{
-+ if (ssock->session) {
-+ gnutls_bye(ssock->session, GNUTLS_SHUT_RDWR);
-+ gnutls_deinit(ssock->session);
-+ ssock->session = NULL;
-+ }
-+
-+ if (ssock->xcred) {
-+ gnutls_certificate_free_credentials(ssock->xcred);
-+ ssock->xcred = NULL;
-+ }
-+
-+ /* Free GnuTLS library */
-+ if (ssock->tls_init_count) {
-+ ssock->tls_init_count--;
-+ tls_deinit();
-+ }
-+
-+ /* Destroy circular buffers */
-+ circ_deinit(&ssock->circ_buf_input);
-+ circ_deinit(&ssock->circ_buf_output);
-+}
-+
-+
-+/* Reset socket state. */
-+static void tls_sock_reset(pj_ssl_sock_t *ssock)
-+{
-+ ssock->connection_state = TLS_STATE_NULL;
-+
-+ tls_close(ssock);
-+
-+ if (ssock->asock) {
-+ pj_activesock_close(ssock->asock);
-+ ssock->asock = NULL;
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ }
-+ if (ssock->sock != PJ_INVALID_SOCKET) {
-+ pj_sock_close(ssock->sock);
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ }
-+
-+ ssock->last_err = tls_last_error = GNUTLS_E_SUCCESS;
-+}
-+
-+
-+/* Get Common Name field string from a general name string */
-+static void tls_cert_get_cn(const pj_str_t *gen_name, pj_str_t *cn)
-+{
-+ pj_str_t CN_sign = {"CN=", 3};
-+ char *p, *q;
-+
-+ pj_bzero(cn, sizeof(cn));
-+
-+ p = pj_strstr(gen_name, &CN_sign);
-+ if (!p)
-+ return;
-+
-+ p += 3; /* shift pointer to value part */
-+ pj_strset(cn, p, gen_name->slen - (p - gen_name->ptr));
-+ q = pj_strchr(cn, ',');
-+ if (q)
-+ cn->slen = q - p;
-+}
-+
-+
-+/* Get certificate info; in case the certificate info is already populated,
-+ * this function will check if the contents need updating by inspecting the
-+ * issuer and the serial number. */
-+static void tls_cert_get_info(pj_pool_t *pool, pj_ssl_cert_info *ci, gnutls_x509_crt_t cert)
-+{
-+ pj_bool_t update_needed;
-+ char buf[512] = { 0 };
-+ size_t bufsize = sizeof(buf);
-+ pj_uint8_t serial_no[64] = { 0 }; /* should be >= sizeof(ci->serial_no) */
-+ size_t serialsize = sizeof(serial_no);
-+ size_t len = sizeof(buf);
-+ int i, ret, seq = 0;
-+ pj_ssl_cert_name_type type;
-+
-+ pj_assert(pool && ci && cert);
-+
-+ /* Get issuer */
-+ gnutls_x509_crt_get_issuer_dn(cert, buf, &bufsize);
-+
-+ /* Get serial no */
-+ gnutls_x509_crt_get_serial(cert, serial_no, &serialsize);
-+
-+ /* Check if the contents need to be updated */
-+ update_needed = pj_strcmp2(&ci->issuer.info, buf) ||
-+ pj_memcmp(ci->serial_no, serial_no, serialsize);
-+ if (!update_needed)
-+ return;
-+
-+ /* Update cert info */
-+
-+ pj_bzero(ci, sizeof(pj_ssl_cert_info));
-+
-+ /* Version */
-+ ci->version = gnutls_x509_crt_get_version(cert);
-+
-+ /* Issuer */
-+ pj_strdup2(pool, &ci->issuer.info, buf);
-+ tls_cert_get_cn(&ci->issuer.info, &ci->issuer.cn);
-+
-+ /* Serial number */
-+ pj_memcpy(ci->serial_no, serial_no, sizeof(ci->serial_no));
-+
-+ /* Subject */
-+ bufsize = sizeof(buf);
-+ gnutls_x509_crt_get_dn(cert, buf, &bufsize);
-+ pj_strdup2(pool, &ci->subject.info, buf);
-+ tls_cert_get_cn(&ci->subject.info, &ci->subject.cn);
-+
-+ /* Validity */
-+ ci->validity.end.sec = gnutls_x509_crt_get_expiration_time(cert);
-+ ci->validity.start.sec = gnutls_x509_crt_get_activation_time(cert);
-+ ci->validity.gmt = 0;
-+
-+ /* Subject Alternative Name extension */
-+ if (ci->version >= 3) {
-+ char out[256] = { 0 };
-+ /* Get the number of all alternate names so that we can allocate
-+ * the correct number of bytes in subj_alt_name */
-+ while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len,
-+ NULL) != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
-+ seq++;
-+
-+ ci->subj_alt_name.entry = pj_pool_calloc(pool, seq,
-+ sizeof(*ci->subj_alt_name.entry));
-+ if (!ci->subj_alt_name.entry) {
-+ tls_last_error = GNUTLS_E_MEMORY_ERROR;
-+ return;
-+ }
-+
-+ /* Now populate the alternative names */
-+ for (i = 0; i < seq; i++) {
-+ len = sizeof(out) - 1;
-+ ret = gnutls_x509_crt_get_subject_alt_name(cert, i, out, &len, NULL);
-+ switch (ret) {
-+ case GNUTLS_SAN_IPADDRESS:
-+ type = PJ_SSL_CERT_NAME_IP;
-+ pj_inet_ntop2(len == sizeof(pj_in6_addr) ? pj_AF_INET6()
-+ : pj_AF_INET(),
-+ out, buf, sizeof(buf));
-+ break;
-+ case GNUTLS_SAN_URI:
-+ type = PJ_SSL_CERT_NAME_URI;
-+ break;
-+ case GNUTLS_SAN_RFC822NAME:
-+ type = PJ_SSL_CERT_NAME_RFC822;
-+ break;
-+ case GNUTLS_SAN_DNSNAME:
-+ type = PJ_SSL_CERT_NAME_DNS;
-+ break;
-+ default:
-+ type = PJ_SSL_CERT_NAME_UNKNOWN;
-+ break;
-+ }
-+
-+ if (len && type != PJ_SSL_CERT_NAME_UNKNOWN) {
-+ ci->subj_alt_name.entry[ci->subj_alt_name.cnt].type = type;
-+ pj_strdup2(pool,
-+ &ci->subj_alt_name.entry[ci->subj_alt_name.cnt].name,
-+ type == PJ_SSL_CERT_NAME_IP ? buf : out);
-+ ci->subj_alt_name.cnt++;
-+ }
-+ }
-+ /* TODO: if no DNS alt. names were found, we could check against
-+ * the commonName as per RFC3280. */
-+ }
-+}
-+
-+static void tls_cert_get_chain_raw(pj_pool_t *pool, pj_ssl_cert_info *ci, const gnutls_datum_t *certs, size_t certs_num)
-+{
-+ size_t i=0;
-+ ci->raw_chain.cert_raw = pj_pool_calloc(pool, certs_num, sizeof(*ci->raw_chain.cert_raw));
-+ ci->raw_chain.cnt = certs_num;
-+ for (i=0; i < certs_num; ++i) {
-+ const pj_str_t crt_raw = {(const char*)certs[i].data, (pj_ssize_t)certs[i].size};
-+ pj_strdup(pool, ci->raw_chain.cert_raw+i, &crt_raw);
-+ }
-+}
-+
-+/* Update local & remote certificates info. This function should be
-+ * called after handshake or renegotiation successfully completed. */
-+static void tls_cert_update(pj_ssl_sock_t *ssock)
-+{
-+ gnutls_x509_crt_t cert = NULL;
-+ const gnutls_datum_t *us;
-+ const gnutls_datum_t *certs;
-+ unsigned int certslen = 0;
-+ int ret = GNUTLS_CERT_INVALID;
-+
-+ pj_assert(ssock->connection_state == TLS_STATE_ESTABLISHED);
-+
-+ /* Get active local certificate */
-+ us = gnutls_certificate_get_ours(ssock->session);
-+ if (!us)
-+ goto us_out;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto us_out;
-+ ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ goto us_out;
-+
-+ tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
-+ tls_cert_get_chain_raw(ssock->pool, &ssock->local_cert_info, us, 1);
-+
-+us_out:
-+ tls_last_error = ret;
-+ if (cert)
-+ gnutls_x509_crt_deinit(cert);
-+ else
-+ pj_bzero(&ssock->local_cert_info, sizeof(pj_ssl_cert_info));
-+
-+ cert = NULL;
-+
-+ /* Get active remote certificate */
-+ certs = gnutls_certificate_get_peers(ssock->session, &certslen);
-+ if (certs == NULL || certslen == 0)
-+ goto peer_out;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto peer_out;
-+
-+ ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto peer_out;
-+
-+ tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
-+ tls_cert_get_chain_raw(ssock->pool, &ssock->remote_cert_info, certs, certslen);
-+
-+peer_out:
-+ tls_last_error = ret;
-+ if (cert)
-+ gnutls_x509_crt_deinit(cert);
-+ else
-+ pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
-+}
-+
-+
-+/* When handshake completed:
-+ * - notify application
-+ * - if handshake failed, reset SSL state
-+ * - return PJ_FALSE when SSL socket instance is destroyed by application. */
-+static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
-+ pj_status_t status)
-+{
-+ pj_bool_t ret = PJ_TRUE;
-+
-+ /* Cancel handshake timer */
-+ if (ssock->timer.id == TIMER_HANDSHAKE_TIMEOUT) {
-+ pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ /* Update certificates info on successful handshake */
-+ if (status == PJ_SUCCESS)
-+ tls_cert_update(ssock);
-+
-+ /* Accepting */
-+ if (ssock->is_server) {
-+ if (status != PJ_SUCCESS) {
-+ /* Handshake failed in accepting, destroy our self silently. */
-+
-+ char errmsg[PJ_ERR_MSG_SIZE];
-+ char buf[PJ_INET6_ADDRSTRLEN + 10];
-+
-+ pj_strerror(status, errmsg, sizeof(errmsg));
-+ PJ_LOG(3, (ssock->pool->obj_name,
-+ "Handshake failed in accepting %s: %s",
-+ pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
-+ errmsg));
-+
-+ /* Workaround for ticket #985 */
-+#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
-+ if (ssock->param.timer_heap) {
-+ pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
-+
-+ tls_sock_reset(ssock);
-+
-+ ssock->timer.id = TIMER_CLOSE;
-+ pj_time_val_normalize(&interval);
-+ if (pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer, &interval) != 0)
-+ {
-+ ssock->timer.id = TIMER_NONE;
-+ pj_ssl_sock_close(ssock);
-+ }
-+ } else
-+#endif /* PJ_WIN32 */
-+ {
-+ pj_ssl_sock_close(ssock);
-+ }
-+
-+ return PJ_FALSE;
-+ }
-+ /* Notify application the newly accepted SSL socket */
-+ if (ssock->param.cb.on_accept_complete)
-+ ret = (*ssock->param.cb.on_accept_complete)
-+ (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr,
-+ pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr));
-+
-+ } else { /* Connecting */
-+ /* On failure, reset SSL socket state first, as app may try to
-+ * reconnect in the callback. */
-+ if (status != PJ_SUCCESS) {
-+ /* Server disconnected us, possibly due to negotiation failure */
-+ tls_sock_reset(ssock);
-+ }
-+ if (ssock->param.cb.on_connect_complete) {
-+
-+ ret = (*ssock->param.cb.on_connect_complete)(ssock, status);
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static write_data_t *alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len)
-+{
-+ send_buf_t *send_buf = &ssock->send_buf;
-+ pj_size_t avail_len, skipped_len = 0;
-+ char *reg1, *reg2;
-+ pj_size_t reg1_len, reg2_len;
-+ write_data_t *p;
-+
-+ /* Check buffer availability */
-+ avail_len = send_buf->max_len - send_buf->len;
-+ if (avail_len < len)
-+ return NULL;
-+
-+ /* If buffer empty, reset start pointer and return it */
-+ if (send_buf->len == 0) {
-+ send_buf->start = send_buf->buf;
-+ send_buf->len = len;
-+ p = (write_data_t*)send_buf->start;
-+ goto init_send_data;
-+ }
-+
-+ /* Free space may be wrapped/splitted into two regions, so let's
-+ * analyze them if any region can hold the write data. */
-+ reg1 = send_buf->start + send_buf->len;
-+ if (reg1 >= send_buf->buf + send_buf->max_len)
-+ reg1 -= send_buf->max_len;
-+ reg1_len = send_buf->max_len - send_buf->len;
-+ if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) {
-+ reg1_len = send_buf->buf + send_buf->max_len - reg1;
-+ reg2 = send_buf->buf;
-+ reg2_len = send_buf->start - send_buf->buf;
-+ } else {
-+ reg2 = NULL;
-+ reg2_len = 0;
-+ }
-+
-+ /* More buffer availability check, note that the write data must be in
-+ * a contigue buffer. */
-+ avail_len = PJ_MAX(reg1_len, reg2_len);
-+ if (avail_len < len)
-+ return NULL;
-+
-+ /* Get the data slot */
-+ if (reg1_len >= len) {
-+ p = (write_data_t*)reg1;
-+ } else {
-+ p = (write_data_t*)reg2;
-+ skipped_len = reg1_len;
-+ }
-+
-+ /* Update buffer length */
-+ send_buf->len += len + skipped_len;
-+
-+init_send_data:
-+ /* Init the new send data */
-+ pj_bzero(p, sizeof(*p));
-+ pj_list_init(p);
-+ pj_list_push_back(&ssock->send_pending, p);
-+
-+ return p;
-+}
-+
-+static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata)
-+{
-+ send_buf_t *buf = &ssock->send_buf;
-+ write_data_t *spl = &ssock->send_pending;
-+
-+ pj_assert(!pj_list_empty(&ssock->send_pending));
-+
-+ /* Free slot from the buffer */
-+ if (spl->next == wdata && spl->prev == wdata) {
-+ /* This is the only data, reset the buffer */
-+ buf->start = buf->buf;
-+ buf->len = 0;
-+ } else if (spl->next == wdata) {
-+ /* This is the first data, shift start pointer of the buffer and
-+ * adjust the buffer length.
-+ */
-+ buf->start = (char*)wdata->next;
-+ if (wdata->next > wdata) {
-+ buf->len -= ((char*)wdata->next - buf->start);
-+ } else {
-+ /* Overlapped */
-+ pj_size_t right_len, left_len;
-+ right_len = buf->buf + buf->max_len - (char*)wdata;
-+ left_len = (char*)wdata->next - buf->buf;
-+ buf->len -= (right_len + left_len);
-+ }
-+ } else if (spl->prev == wdata) {
-+ /* This is the last data, just adjust the buffer length */
-+ if (wdata->prev < wdata) {
-+ pj_size_t jump_len;
-+ jump_len = (char*)wdata -
-+ ((char*)wdata->prev + wdata->prev->record_len);
-+ buf->len -= (wdata->record_len + jump_len);
-+ } else {
-+ /* Overlapped */
-+ pj_size_t right_len, left_len;
-+ right_len = buf->buf + buf->max_len -
-+ ((char*)wdata->prev + wdata->prev->record_len);
-+ left_len = (char*)wdata + wdata->record_len - buf->buf;
-+ buf->len -= (right_len + left_len);
-+ }
-+ }
-+ /* For data in the middle buffer, just do nothing on the buffer. The slot
-+ * will be freed later when freeing the first/last data. */
-+
-+ /* Remove the data from send pending list */
-+ pj_list_erase(wdata);
-+}
-+
-+#if 0
-+/* Just for testing send buffer alloc/free */
-+#include <pj/rand.h>
-+pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool)
-+{
-+ enum { MAX_CHUNK_NUM = 20 };
-+ unsigned chunk_size, chunk_cnt, i;
-+ write_data_t *wdata[MAX_CHUNK_NUM] = {0};
-+ pj_time_val now;
-+ pj_ssl_sock_t *ssock = NULL;
-+ pj_ssl_sock_param param;
-+ pj_status_t status;
-+
-+ pj_gettimeofday(&now);
-+ pj_srand((unsigned)now.sec);
-+
-+ pj_ssl_sock_param_default(&param);
-+ status = pj_ssl_sock_create(pool, &param, &ssock);
-+ if (status != PJ_SUCCESS) {
-+ return status;
-+ }
-+
-+ if (ssock->send_buf.max_len == 0) {
-+ ssock->send_buf.buf = (char *)
-+ pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+ }
-+
-+ chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2;
-+ chunk_cnt = 0;
-+ for (i = 0; i < MAX_CHUNK_NUM; i++) {
-+ wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321);
-+ if (wdata[i])
-+ chunk_cnt++;
-+ else
-+ break;
-+ }
-+
-+ while (chunk_cnt) {
-+ i = pj_rand() % MAX_CHUNK_NUM;
-+ if (wdata[i]) {
-+ free_send_data(ssock, wdata[i]);
-+ wdata[i] = NULL;
-+ chunk_cnt--;
-+ }
-+ }
-+
-+ if (ssock->send_buf.len != 0)
-+ status = PJ_EBUG;
-+
-+ pj_ssl_sock_close(ssock);
-+ return status;
-+}
-+#endif
-+
-+/* Flush write circular buffer to network socket. */
-+static pj_status_t flush_circ_buf_output(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ pj_size_t orig_len, unsigned flags)
-+{
-+ pj_ssize_t len;
-+ write_data_t *wdata;
-+ pj_size_t needed_len;
-+ pj_status_t status;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Check if there is data in the circular buffer, flush it if any */
-+ if (circ_empty(&ssock->circ_buf_output)) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return PJ_SUCCESS;
-+ }
-+
-+ len = circ_size(&ssock->circ_buf_output);
-+
-+ /* Calculate buffer size needed, and align it to 8 */
-+ needed_len = len + sizeof(write_data_t);
-+ needed_len = ((needed_len + 7) >> 3) << 3;
-+
-+ /* Allocate buffer for send data */
-+ wdata = alloc_send_data(ssock, needed_len);
-+ if (wdata == NULL) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Copy the data and set its properties into the send data */
-+ pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t));
-+ wdata->key.user_data = wdata;
-+ wdata->app_key = send_key;
-+ wdata->record_len = needed_len;
-+ wdata->data_len = len;
-+ wdata->plain_data_len = orig_len;
-+ wdata->flags = flags;
-+ circ_read(&ssock->circ_buf_output, (pj_uint8_t *)&wdata->data, len);
-+
-+ /* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ /* Send it */
-+ if (ssock->param.sock_type == pj_SOCK_STREAM()) {
-+ status = pj_activesock_send(ssock->asock, &wdata->key,
-+ wdata->data.content, &len,
-+ flags);
-+ } else {
-+ status = pj_activesock_sendto(ssock->asock, &wdata->key,
-+ wdata->data.content, &len,
-+ flags,
-+ (pj_sockaddr_t*)&ssock->rem_addr,
-+ ssock->addr_len);
-+ }
-+
-+ if (status != PJ_EPENDING) {
-+ /* When the sending is not pending, remove the wdata from send
-+ * pending list. */
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ free_send_data(ssock, wdata);
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ }
-+
-+ return status;
-+}
-+
-+static void on_timer(pj_timer_heap_t *th, struct pj_timer_entry *te)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)te->user_data;
-+ int timer_id = te->id;
-+
-+ te->id = TIMER_NONE;
-+
-+ PJ_UNUSED_ARG(th);
-+
-+ switch (timer_id) {
-+ case TIMER_HANDSHAKE_TIMEOUT:
-+ PJ_LOG(1, (ssock->pool->obj_name, "TLS timeout after %d.%ds",
-+ ssock->param.timeout.sec, ssock->param.timeout.msec));
-+
-+ on_handshake_complete(ssock, PJ_ETIMEDOUT);
-+ break;
-+ case TIMER_CLOSE:
-+ pj_ssl_sock_close(ssock);
-+ break;
-+ default:
-+ pj_assert(!"Unknown timer");
-+ break;
-+ }
-+}
-+
-+
-+/* Try to perform an asynchronous handshake */
-+static pj_status_t tls_try_handshake(pj_ssl_sock_t *ssock)
-+{
-+ int ret;
-+ pj_status_t status;
-+
-+ /* Perform SSL handshake */
-+ ret = gnutls_handshake(ssock->session);
-+
-+ status = flush_circ_buf_output(ssock, &ssock->handshake_op_key, 0, 0);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ if (ret == GNUTLS_E_SUCCESS) {
-+ /* System are GO */
-+ ssock->connection_state = TLS_STATE_ESTABLISHED;
-+ status = PJ_SUCCESS;
-+ } else if (!gnutls_error_is_fatal(ret)) {
-+ /* Non fatal error, retry later (busy or again) */
-+ status = PJ_EPENDING;
-+ } else {
-+ /* Fatal error invalidates session, no fallback */
-+ status = PJ_EINVAL;
-+ }
-+
-+ tls_last_error = ret;
-+
-+ return status;
-+}
-+
-+
-+/*
-+ *******************************************************************
-+ * Active socket callbacks.
-+ *******************************************************************
-+ */
-+
-+/* PJ_TRUE asks the socket to read more data, PJ_FALSE takes it off the queue */
-+static pj_bool_t asock_on_data_read(pj_activesock_t *asock, void *data,
-+ pj_size_t size, pj_status_t status,
-+ pj_size_t *remainder)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)
-+ pj_activesock_get_user_data(asock);
-+
-+ pj_size_t app_remainder = 0;
-+
-+ if (data && size > 0) {
-+ /* Push data into input circular buffer (for GnuTLS) */
-+ pj_lock_acquire(ssock->circ_buf_input_mutex);
-+ circ_write(&ssock->circ_buf_input, data, size);
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+ }
-+
-+ /* Check if SSL handshake hasn't finished yet */
-+ if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
-+ pj_bool_t ret = PJ_TRUE;
-+
-+ if (status == PJ_SUCCESS)
-+ status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (status != PJ_EPENDING)
-+ ret = on_handshake_complete(ssock, status);
-+
-+ return ret;
-+ }
-+
-+ /* See if there is any decrypted data for the application */
-+ if (ssock->read_started) {
-+ do {
-+ /* Get read data structure at the end of the data */
-+ read_data_t *app_read_data = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
-+ int app_data_size = (int)(ssock->read_size - app_read_data->len);
-+
-+ /* Decrypt received data using GnuTLS (will read our input
-+ * circular buffer) */
-+ int decrypted_size = gnutls_record_recv(ssock->session,
-+ ((read_data_t *)app_read_data->data) +
-+ app_read_data->len,
-+ app_data_size);
-+
-+ if (decrypted_size > 0 || status != PJ_SUCCESS) {
-+ if (ssock->param.cb.on_data_read) {
-+ pj_bool_t ret;
-+ app_remainder = 0;
-+
-+ if (decrypted_size > 0)
-+ app_read_data->len += decrypted_size;
-+
-+ ret = (*ssock->param.cb.on_data_read)(ssock,
-+ app_read_data->data,
-+ app_read_data->len,
-+ status,
-+ &app_remainder);
-+
-+ if (!ret) {
-+ /* We've been destroyed */
-+ return PJ_FALSE;
-+ }
-+
-+ /* Application may have left some data to be consumed
-+ * later as remainder */
-+ app_read_data->len = app_remainder;
-+ }
-+
-+ /* Active socket signalled connection closed/error, this has
-+ * been signalled to the application along with any remaining
-+ * buffer. So, let's just reset SSL socket now. */
-+ if (status != PJ_SUCCESS) {
-+ tls_sock_reset(ssock);
-+ return PJ_FALSE;
-+ }
-+ } else if (decrypted_size == 0) {
-+ /* Nothing more to read */
-+
-+ return PJ_TRUE;
-+ } else if (decrypted_size == GNUTLS_E_AGAIN ||
-+ decrypted_size == GNUTLS_E_INTERRUPTED) {
-+ return PJ_TRUE;
-+ } else if (decrypted_size == GNUTLS_E_REHANDSHAKE) {
-+ /* Seems like we are renegotiating */
-+ pj_status_t try_handshake_status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (try_handshake_status != PJ_EPENDING) {
-+ if (!on_handshake_complete(ssock, try_handshake_status)) {
-+ return PJ_FALSE;
-+ }
-+ }
-+
-+ if (try_handshake_status != PJ_SUCCESS &&
-+ try_handshake_status != PJ_EPENDING) {
-+ return PJ_FALSE;
-+ }
-+ } else if (!gnutls_error_is_fatal(decrypted_size)) {
-+ /* non-fatal error, let's just continue */
-+ } else {
-+ return PJ_FALSE;
-+ }
-+ } while (PJ_TRUE);
-+ }
-+
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time new data is available from the active socket */
-+static pj_bool_t asock_on_data_sent(pj_activesock_t *asock,
-+ pj_ioqueue_op_key_t *send_key,
-+ pj_ssize_t sent)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)pj_activesock_get_user_data(asock);
-+
-+ PJ_UNUSED_ARG(send_key);
-+ PJ_UNUSED_ARG(sent);
-+
-+ if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
-+ /* Initial handshaking */
-+ pj_status_t status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (status != PJ_EPENDING)
-+ return on_handshake_complete(ssock, status);
-+
-+ } else if (send_key != &ssock->handshake_op_key) {
-+ /* Some data has been sent, notify application */
-+ write_data_t *wdata = (write_data_t*)send_key->user_data;
-+ if (ssock->param.cb.on_data_sent) {
-+ pj_bool_t ret;
-+ pj_ssize_t sent_len;
-+
-+ sent_len = sent > 0 ? wdata->plain_data_len : sent;
-+
-+ ret = (*ssock->param.cb.on_data_sent)(ssock, wdata->app_key,
-+ sent_len);
-+ if (!ret) {
-+ /* We've been destroyed */
-+ return PJ_FALSE;
-+ }
-+ }
-+
-+ /* Update write buffer state */
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ free_send_data(ssock, wdata);
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ } else {
-+ /* SSL re-negotiation is on-progress, just do nothing */
-+ /* FIXME: check if this is valid for GnuTLS too */
-+ }
-+
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time a new connection has been accepted (server) */
-+static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
-+ pj_sock_t newsock,
-+ const pj_sockaddr_t *src_addr,
-+ int src_addr_len)
-+{
-+ pj_ssl_sock_t *ssock_parent = (pj_ssl_sock_t *)
-+ pj_activesock_get_user_data(asock);
-+
-+ pj_ssl_sock_t *ssock;
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ unsigned int i;
-+ pj_status_t status;
-+
-+ PJ_UNUSED_ARG(src_addr_len);
-+
-+ /* Create new SSL socket instance */
-+ status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->newsock_param,
-+ &ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Update new SSL socket attributes */
-+ ssock->sock = newsock;
-+ ssock->parent = ssock_parent;
-+ ssock->is_server = PJ_TRUE;
-+ if (ssock_parent->cert) {
-+ status = pj_ssl_sock_set_certificate(ssock, ssock->pool,
-+ ssock_parent->cert);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+ }
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 1,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_return;
-+
-+ /* Update local address */
-+ ssock->addr_len = src_addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS) {
-+ /* This fails on few envs, e.g: win IOCP, just tolerate this and
-+ * use parent local address instead.
-+ */
-+ pj_sockaddr_cp(&ssock->local_addr, &ssock_parent->local_addr);
-+ }
-+
-+ /* Set remote address */
-+ pj_sockaddr_cp(&ssock->rem_addr, src_addr);
-+
-+ /* Create SSL context */
-+ status = tls_open(ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare read buffer */
-+ ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
-+ ssock->param.async_cnt,
-+ sizeof(void*));
-+ if (!ssock->asock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
-+ ssock->pool,
-+ ssock->param.read_buffer_size +
-+ sizeof(read_data_t*));
-+ if (!ssock->asock_rbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_data_read = asock_on_data_read;
-+ asock_cb.on_data_sent = asock_on_data_sent;
-+
-+ status = pj_activesock_create(ssock->pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Start reading */
-+ status = pj_activesock_start_read2(ssock->asock, ssock->pool,
-+ (unsigned)ssock->param.read_buffer_size,
-+ ssock->asock_rbuf,
-+ PJ_IOQUEUE_ALWAYS_ASYNC);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare write/send state */
-+ pj_assert(ssock->send_buf.max_len == 0);
-+ ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ if (!ssock->send_buf.buf)
-+ return PJ_ENOMEM;
-+
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+
-+ /* Start handshake timer */
-+ if (ssock->param.timer_heap &&
-+ (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0)) {
-+ pj_assert(ssock->timer.id == TIMER_NONE);
-+ ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
-+ status = pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer,
-+ &ssock->param.timeout);
-+ if (status != PJ_SUCCESS)
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ /* Start SSL handshake */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+
-+ status = tls_try_handshake(ssock);
-+
-+on_return:
-+ if (ssock && status != PJ_EPENDING)
-+ on_handshake_complete(ssock, status);
-+
-+ /* Must return PJ_TRUE whatever happened, as active socket must
-+ * continue listening.
-+ */
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time a new connection has been completed (client) */
-+static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
-+ pj_status_t status)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)
-+ pj_activesock_get_user_data(asock);
-+
-+ unsigned int i;
-+ int ret;
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Update local address */
-+ ssock->addr_len = sizeof(pj_sockaddr);
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Create SSL context */
-+ status = tls_open(ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare read buffer */
-+ ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
-+ ssock->param.async_cnt,
-+ sizeof(void *));
-+ if (!ssock->asock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
-+ ssock->pool,
-+ ssock->param.read_buffer_size +
-+ sizeof(read_data_t *));
-+ if (!ssock->asock_rbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Start read */
-+ status = pj_activesock_start_read2(ssock->asock, ssock->pool,
-+ (unsigned) ssock->param.read_buffer_size,
-+ ssock->asock_rbuf,
-+ PJ_IOQUEUE_ALWAYS_ASYNC);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare write/send state */
-+ pj_assert(ssock->send_buf.max_len == 0);
-+ ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ if (!ssock->send_buf.buf)
-+ return PJ_ENOMEM;
-+
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+
-+ /* Set server name to connect */
-+ if (ssock->param.server_name.slen) {
-+ /* Server name is null terminated already */
-+ ret = gnutls_server_name_set(ssock->session, GNUTLS_NAME_DNS,
-+ ssock->param.server_name.ptr,
-+ ssock->param.server_name.slen);
-+ if (ret < 0) {
-+ PJ_LOG(3, (ssock->pool->obj_name,
-+ "gnutls_server_name_set() failed: %s",
-+ gnutls_strerror(ret)));
-+ }
-+ }
-+
-+ /* Start handshake */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+
-+ status = tls_try_handshake(ssock);
-+ if (status != PJ_EPENDING)
-+ goto on_return;
-+
-+ return PJ_TRUE;
-+
-+on_return:
-+ return on_handshake_complete(ssock, status);
-+}
-+
-+static void tls_ciphers_fill(void)
-+{
-+ if (!tls_available_ciphers) {
-+ tls_init();
-+ tls_deinit();
-+ }
-+}
-+
-+/*
-+ *******************************************************************
-+ * API
-+ *******************************************************************
-+ */
-+
-+/* Load credentials from files. */
-+PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
-+ const pj_str_t *CA_file,
-+ const pj_str_t *cert_file,
-+ const pj_str_t *privkey_file,
-+ const pj_str_t *privkey_pass,
-+ pj_ssl_cert_t **p_cert)
-+{
-+ return pj_ssl_cert_load_from_files2(pool, CA_file, NULL, cert_file,
-+ privkey_file, privkey_pass, p_cert);
-+}
-+
-+/* Load credentials from files. */
-+PJ_DECL(pj_status_t) pj_ssl_cert_load_from_files2(
-+ pj_pool_t *pool,
-+ const pj_str_t *CA_file,
-+ const pj_str_t *CA_path,
-+ const pj_str_t *cert_file,
-+ const pj_str_t *privkey_file,
-+ const pj_str_t *privkey_pass,
-+ pj_ssl_cert_t **p_cert)
-+{
-+ pj_ssl_cert_t *cert;
-+
-+ PJ_ASSERT_RETURN(pool && (CA_file || CA_path) && cert_file &&
-+ privkey_file,
-+ PJ_EINVAL);
-+
-+ cert = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
-+ if (CA_file) {
-+ pj_strdup_with_null(pool, &cert->CA_file, CA_file);
-+ }
-+ if (CA_path) {
-+ pj_strdup_with_null(pool, &cert->CA_path, CA_path);
-+ }
-+ pj_strdup_with_null(pool, &cert->cert_file, cert_file);
-+ pj_strdup_with_null(pool, &cert->privkey_file, privkey_file);
-+ pj_strdup_with_null(pool, &cert->privkey_pass, privkey_pass);
-+
-+ *p_cert = cert;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+/* Store credentials. */
-+PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_ssl_cert_t *cert)
-+{
-+ pj_ssl_cert_t *cert_;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && cert, PJ_EINVAL);
-+
-+ cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
-+ pj_memcpy(cert_, cert, sizeof(cert));
-+ pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
-+ pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
-+ pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
-+ pj_strdup_with_null(pool, &cert_->privkey_file, &cert->privkey_file);
-+ pj_strdup_with_null(pool, &cert_->privkey_pass, &cert->privkey_pass);
-+
-+ ssock->cert = cert_;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Get available ciphers. */
-+PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
-+ unsigned *cipher_num)
-+{
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
-+
-+ tls_ciphers_fill();
-+
-+ if (!tls_available_ciphers) {
-+ *cipher_num = 0;
-+ return PJ_ENOTFOUND;
-+ }
-+
-+ *cipher_num = PJ_MIN(*cipher_num, tls_available_ciphers);
-+
-+ for (i = 0; i < *cipher_num; ++i)
-+ ciphers[i] = tls_ciphers[i].id;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Get cipher name string. */
-+PJ_DEF(const char *)pj_ssl_cipher_name(pj_ssl_cipher cipher)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (cipher == tls_ciphers[i].id)
-+ return tls_ciphers[i].name;
-+ }
-+
-+ return NULL;
-+}
-+
-+
-+/* Get cipher identifier. */
-+PJ_DEF(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (!pj_ansi_stricmp(tls_ciphers[i].name, cipher_name))
-+ return tls_ciphers[i].id;
-+ }
-+
-+ return PJ_TLS_UNKNOWN_CIPHER;
-+}
-+
-+
-+/* Check if the specified cipher is supported by the TLS backend. */
-+PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (cipher == tls_ciphers[i].id)
-+ return PJ_TRUE;
-+ }
-+
-+ return PJ_FALSE;
-+}
-+
-+/* Create SSL socket instance. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_create(pj_pool_t *pool,
-+ const pj_ssl_sock_param *param,
-+ pj_ssl_sock_t **p_ssock)
-+{
-+ pj_ssl_sock_t *ssock;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(param->sock_type == pj_SOCK_STREAM(), PJ_ENOTSUP);
-+
-+ pool = pj_pool_create(pool->factory, "tls%p", 512, 512, NULL);
-+
-+ /* Create secure socket */
-+ ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
-+ ssock->pool = pool;
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ ssock->connection_state = TLS_STATE_NULL;
-+ pj_list_init(&ssock->write_pending);
-+ pj_list_init(&ssock->write_pending_empty);
-+ pj_list_init(&ssock->send_pending);
-+ pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer);
-+ pj_ioqueue_op_key_init(&ssock->handshake_op_key,
-+ sizeof(pj_ioqueue_op_key_t));
-+
-+ /* Create secure socket mutex */
-+ status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_output_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Create input circular buffer mutex */
-+ status = pj_lock_create_simple_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_input_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Create output circular buffer mutex */
-+ status = pj_lock_create_simple_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_output_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Init secure socket param */
-+ ssock->param = *param;
-+ ssock->param.read_buffer_size = ((ssock->param.read_buffer_size + 7) >> 3) << 3;
-+
-+ if (param->ciphers_num > 0) {
-+ unsigned int i;
-+ ssock->param.ciphers = (pj_ssl_cipher *)
-+ pj_pool_calloc(pool, param->ciphers_num,
-+ sizeof(pj_ssl_cipher));
-+ if (!ssock->param.ciphers)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < param->ciphers_num; ++i)
-+ ssock->param.ciphers[i] = param->ciphers[i];
-+ }
-+
-+ /* Server name must be null-terminated */
-+ pj_strdup_with_null(pool, &ssock->param.server_name, &param->server_name);
-+
-+ /* Finally */
-+ *p_ssock = ssock;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ * Close the secure socket. This will unregister the socket from the
-+ * ioqueue and ultimately close the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
-+{
-+ pj_pool_t *pool;
-+
-+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
-+
-+ if (!ssock->pool)
-+ return PJ_SUCCESS;
-+
-+ if (ssock->timer.id != TIMER_NONE) {
-+ pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ tls_sock_reset(ssock);
-+
-+ pj_lock_destroy(ssock->circ_buf_output_mutex);
-+ pj_lock_destroy(ssock->circ_buf_input_mutex);
-+
-+ pool = ssock->pool;
-+ ssock->pool = NULL;
-+ if (pool)
-+ pj_pool_release(pool);
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Associate arbitrary data with the secure socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data(pj_ssl_sock_t *ssock,
-+ void *user_data)
-+{
-+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
-+
-+ ssock->param.user_data = user_data;
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Retrieve the user data previously associated with this secure socket. */
-+PJ_DEF(void *)pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
-+{
-+ PJ_ASSERT_RETURN(ssock, NULL);
-+
-+ return ssock->param.user_data;
-+}
-+
-+
-+/* Retrieve the local address and port used by specified SSL socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
-+ pj_ssl_sock_info *info)
-+{
-+ pj_bzero(info, sizeof(*info));
-+
-+ /* Established flag */
-+ info->established = (ssock->connection_state == TLS_STATE_ESTABLISHED);
-+
-+ /* Protocol */
-+ info->proto = ssock->param.proto;
-+
-+ /* Local address */
-+ pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
-+
-+ if (info->established) {
-+ int i;
-+ gnutls_cipher_algorithm_t lookup;
-+ gnutls_cipher_algorithm_t cipher;
-+
-+ /* Current cipher */
-+ cipher = gnutls_cipher_get(ssock->session);
-+ for (i = 0; ; i++) {
-+ unsigned char id[2];
-+ const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
-+ NULL, &lookup, NULL,
-+ NULL);
-+ if (suite) {
-+ if (lookup == cipher) {
-+ info->cipher = (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ break;
-+ }
-+ } else
-+ break;
-+ }
-+
-+ /* Remote address */
-+ pj_sockaddr_cp(&info->remote_addr, &ssock->rem_addr);
-+
-+ /* Certificates info */
-+ info->local_cert_info = &ssock->local_cert_info;
-+ info->remote_cert_info = &ssock->remote_cert_info;
-+
-+ /* Verification status */
-+ info->verify_status = ssock->verify_status;
-+ }
-+
-+ /* Last known GnuTLS error code */
-+ info->last_native_err = ssock->last_err;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Starts read operation on this secure socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_read(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ pj_uint32_t flags)
-+{
-+ void **readbuf;
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ readbuf = (void**) pj_pool_calloc(pool, ssock->param.async_cnt,
-+ sizeof(void *));
-+ if (!readbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ readbuf[i] = pj_pool_alloc(pool, buff_size);
-+ if (!readbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
-+}
-+
-+
-+/*
-+ * Same as #pj_ssl_sock_start_read(), except that the application
-+ * supplies the buffers for the read operation so that the acive socket
-+ * does not have to allocate the buffers.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ void *readbuf[],
-+ pj_uint32_t flags)
-+{
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && buff_size && readbuf, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Create SSL socket read buffer */
-+ ssock->ssock_rbuf = (read_data_t*)pj_pool_calloc(pool,
-+ ssock->param.async_cnt,
-+ sizeof(read_data_t));
-+ if (!ssock->ssock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ /* Store SSL socket read buffer pointer in the activesock read buffer */
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ read_data_t **p_ssock_rbuf =
-+ OFFSET_OF_READ_DATA_PTR(ssock, ssock->asock_rbuf[i]);
-+
-+ ssock->ssock_rbuf[i].data = readbuf[i];
-+ ssock->ssock_rbuf[i].len = 0;
-+
-+ *p_ssock_rbuf = &ssock->ssock_rbuf[i];
-+ }
-+
-+ ssock->read_size = buff_size;
-+ ssock->read_started = PJ_TRUE;
-+ ssock->read_flags = flags;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ * Same as pj_ssl_sock_start_read(), except that this function is used
-+ * only for datagram sockets, and it will trigger \a on_data_recvfrom()
-+ * callback instead.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ pj_uint32_t flags)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(pool);
-+ PJ_UNUSED_ARG(buff_size);
-+ PJ_UNUSED_ARG(flags);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+
-+/*
-+ * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
-+ * operation takes the buffer from the argument rather than creating
-+ * new ones.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ void *readbuf[],
-+ pj_uint32_t flags)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(pool);
-+ PJ_UNUSED_ARG(buff_size);
-+ PJ_UNUSED_ARG(readbuf);
-+ PJ_UNUSED_ARG(flags);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+
-+/*
-+ * Write the plain data to GnuTLS, it will be encrypted by gnutls_record_send()
-+ * and sent via tls_data_push. Note that re-negotitation may be on progress, so
-+ * sending data should be delayed until re-negotiation is completed.
-+ */
-+static pj_status_t tls_write(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t size, unsigned flags)
-+{
-+ pj_status_t status;
-+ int nwritten;
-+ pj_ssize_t total_written = 0;
-+
-+ /* Ask GnuTLS to encrypt our plaintext now. GnuTLS will use the push
-+ * callback to actually write the encrypted bytes into our output circular
-+ * buffer. GnuTLS may refuse to "send" everything at once, but since we are
-+ * not really sending now, we will just call it again now until it succeeds
-+ * (or fails in a fatal way). */
-+ while (total_written < size) {
-+ /* Try encrypting using GnuTLS */
-+ nwritten = gnutls_record_send(ssock->session, ((read_data_t *)data) + total_written,
-+ size);
-+
-+ if (nwritten > 0) {
-+ /* Good, some data was encrypted and written */
-+ total_written += nwritten;
-+ } else {
-+ /* Normally we would have to retry record_send but our internal
-+ * state has not changed, so we have to ask for more data first.
-+ * We will just try again later, although this should never happen.
-+ */
-+ return tls_status_from_err(ssock, nwritten);
-+ }
-+ }
-+
-+ /* All encrypted data is written to the output circular buffer;
-+ * now send it on the socket (or notify problem). */
-+ if (total_written == size)
-+ status = flush_circ_buf_output(ssock, send_key, size, flags);
-+ else
-+ status = PJ_ENOMEM;
-+
-+ return status;
-+}
-+
-+
-+/* Flush delayed data sending in the write pending list. */
-+static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock)
-+{
-+ /* Check for another ongoing flush */
-+ if (ssock->flushing_write_pend) {
-+ return PJ_EBUSY;
-+ }
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Again, check for another ongoing flush */
-+ if (ssock->flushing_write_pend) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ return PJ_EBUSY;
-+ }
-+
-+ /* Set ongoing flush flag */
-+ ssock->flushing_write_pend = PJ_TRUE;
-+
-+ while (!pj_list_empty(&ssock->write_pending)) {
-+ write_data_t *wp;
-+ pj_status_t status;
-+
-+ wp = ssock->write_pending.next;
-+
-+ /* Ticket #1573: Don't hold mutex while calling socket send. */
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ status = tls_write(ssock, &wp->key, wp->data.ptr,
-+ wp->plain_data_len, wp->flags);
-+ if (status != PJ_SUCCESS) {
-+ /* Reset ongoing flush flag first. */
-+ ssock->flushing_write_pend = PJ_FALSE;
-+ return status;
-+ }
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ pj_list_erase(wp);
-+ pj_list_push_back(&ssock->write_pending_empty, wp);
-+ }
-+
-+ /* Reset ongoing flush flag */
-+ ssock->flushing_write_pend = PJ_FALSE;
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Sending is delayed, push back the sending data into pending list. */
-+static pj_status_t delay_send(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t size,
-+ unsigned flags)
-+{
-+ write_data_t *wp;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Init write pending instance */
-+ if (!pj_list_empty(&ssock->write_pending_empty)) {
-+ wp = ssock->write_pending_empty.next;
-+ pj_list_erase(wp);
-+ } else {
-+ wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t);
-+ }
-+
-+ wp->app_key = send_key;
-+ wp->plain_data_len = size;
-+ wp->data.ptr = data;
-+ wp->flags = flags;
-+
-+ pj_list_push_back(&ssock->write_pending, wp);
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ /* Must return PJ_EPENDING */
-+ return PJ_EPENDING;
-+}
-+
-+
-+/**
-+ * Send data using the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_send(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t *size,
-+ unsigned flags)
-+{
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && data && size && (*size > 0), PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state==TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Flush delayed send first. Sending data might be delayed when
-+ * re-negotiation is on-progress. */
-+ status = flush_delayed_send(ssock);
-+ if (status == PJ_EBUSY) {
-+ /* Re-negotiation or flushing is on progress, delay sending */
-+ status = delay_send(ssock, send_key, data, *size, flags);
-+ goto on_return;
-+ } else if (status != PJ_SUCCESS) {
-+ goto on_return;
-+ }
-+
-+ /* Write data to SSL */
-+ status = tls_write(ssock, send_key, data, *size, flags);
-+ if (status == PJ_EBUSY) {
-+ /* Re-negotiation is on progress, delay sending */
-+ status = delay_send(ssock, send_key, data, *size, flags);
-+ }
-+
-+on_return:
-+ return status;
-+}
-+
-+
-+/**
-+ * Send datagram using the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t *size,
-+ unsigned flags,
-+ const pj_sockaddr_t *addr, int addr_len)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(send_key);
-+ PJ_UNUSED_ARG(data);
-+ PJ_UNUSED_ARG(size);
-+ PJ_UNUSED_ARG(flags);
-+ PJ_UNUSED_ARG(addr);
-+ PJ_UNUSED_ARG(addr_len);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+/**
-+ * Starts asynchronous socket accept() operations on this secure socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ int addr_len)
-+{
-+ return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len,
-+ &ssock->param);
-+}
-+
-+/**
-+ * Starts asynchronous socket accept() operations on this secure socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_accept2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ int addr_len,
-+ const pj_ssl_sock_param *newsock_param)
-+{
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
-+
-+ /* Verify new socket parameters */
-+ if (newsock_param->grp_lock != ssock->param.grp_lock ||
-+ newsock_param->sock_af != ssock->param.sock_af ||
-+ newsock_param->sock_type != ssock->param.sock_type)
-+ {
-+ return PJ_EINVAL;
-+ }
-+
-+ /* Create socket */
-+ status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
-+ &ssock->sock);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Apply SO_REUSEADDR */
-+ if (ssock->param.reuse_addr) {
-+ int enabled = 1;
-+ status = pj_sock_setsockopt(ssock->sock, pj_SOL_SOCKET(),
-+ pj_SO_REUSEADDR(),
-+ &enabled, sizeof(enabled));
-+ if (status != PJ_SUCCESS) {
-+ PJ_PERROR(4,(ssock->pool->obj_name, status,
-+ "Warning: error applying SO_REUSEADDR"));
-+ }
-+ }
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 2,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_error;
-+
-+ /* Bind socket */
-+ status = pj_sock_bind(ssock->sock, localaddr, addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Start listening to the address */
-+ status = pj_sock_listen(ssock->sock, PJ_SOMAXCONN);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_accept_complete = asock_on_accept_complete;
-+
-+ status = pj_activesock_create(pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Start accepting */
-+ pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param);
-+ status = pj_activesock_start_accept(ssock->asock, pool);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Update local address */
-+ ssock->addr_len = addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS)
-+ pj_sockaddr_cp(&ssock->local_addr, localaddr);
-+
-+ ssock->is_server = PJ_TRUE;
-+
-+ return PJ_SUCCESS;
-+
-+on_error:
-+ tls_sock_reset(ssock);
-+ return status;
-+}
-+
-+
-+/**
-+ * Starts asynchronous socket connect() operation.
-+ */
-+PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ const pj_sockaddr_t *remaddr,
-+ int addr_len)
-+{
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
-+ PJ_EINVAL);
-+
-+ /* Create socket */
-+ status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
-+ &ssock->sock);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 2,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_error;
-+
-+ /* Bind socket */
-+ status = pj_sock_bind(ssock->sock, localaddr, addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_connect_complete = asock_on_connect_complete;
-+ asock_cb.on_data_read = asock_on_data_read;
-+ asock_cb.on_data_sent = asock_on_data_sent;
-+
-+ status = pj_activesock_create(pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Save remote address */
-+ pj_sockaddr_cp(&ssock->rem_addr, remaddr);
-+
-+ /* Start timer */
-+ if (ssock->param.timer_heap &&
-+ (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0))
-+ {
-+ pj_assert(ssock->timer.id == TIMER_NONE);
-+ ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
-+ status = pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer,
-+ &ssock->param.timeout);
-+ if (status != PJ_SUCCESS)
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
-+ addr_len);
-+
-+ if (status == PJ_SUCCESS)
-+ asock_on_connect_complete(ssock->asock, PJ_SUCCESS);
-+ else if (status != PJ_EPENDING)
-+ goto on_error;
-+
-+ /* Update local address */
-+ ssock->addr_len = addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ /* Note that we may not get an IP address here. This can
-+ * happen for example on Windows, where getsockname()
-+ * would return 0.0.0.0 if socket has just started the
-+ * async connect. In this case, just leave the local
-+ * address with 0.0.0.0 for now; it will be updated
-+ * once the socket is established.
-+ */
-+
-+ /* Update socket state */
-+ ssock->is_server = PJ_FALSE;
-+
-+ return PJ_EPENDING;
-+
-+on_error:
-+ tls_sock_reset(ssock);
-+ return status;
-+}
-+
-+
-+PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
-+{
-+ int status;
-+
-+ /* Nothing established yet */
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Cannot renegotiate; we're a client */
-+ /* FIXME: in fact maybe that's not true */
-+ PJ_ASSERT_RETURN(!ssock->is_server, PJ_EINVALIDOP);
-+
-+ /* First call gnutls_rehandshake() to see if this is even possible */
-+ status = gnutls_rehandshake(ssock->session);
-+
-+ if (status == GNUTLS_E_SUCCESS) {
-+ /* Rehandshake is possible, so try a GnuTLS handshake now. The eventual
-+ * gnutls_record_recv() calls could return a few specific values during
-+ * this state:
-+ *
-+ * - GNUTLS_E_REHANDSHAKE: rehandshake message processing
-+ * - GNUTLS_E_WARNING_ALERT_RECEIVED: client does not wish to
-+ * renegotiate
-+ */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+ status = tls_try_handshake(ssock);
-+
-+ return status;
-+ } else {
-+ return tls_status_from_err(ssock, status);
-+ }
-+}
-+
-+#endif /* PJ_HAS_SSL_SOCK */
-diff -ru a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
---- a/pjlib/src/pj/ssl_sock_ossl.c 2017-01-24 00:41:05.000000000 -0500
-+++ b/pjlib/src/pj/ssl_sock_ossl.c 2017-06-08 13:42:15.188809557 -0400
-@@ -32,8 +32,10 @@
- #include <pj/timer.h>
-
-
--/* Only build when PJ_HAS_SSL_SOCK is enabled */
--#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK!=0
-+/* Only build when PJ_HAS_SSL_SOCK is enabled and when PJ_HAS_TLS_SOCK is
-+ * disabled (meaning GnuTLS is off) */
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
-
- #define THIS_FILE "ssl_sock_ossl.c"
-
-diff -ru a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c
---- a/pjmedia/src/pjmedia/transport_srtp.c 2017-01-10 23:38:29.000000000 -0500
-+++ b/pjmedia/src/pjmedia/transport_srtp.c 2017-06-08 13:43:29.727001721 -0400
-@@ -30,7 +30,8 @@
-
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
-
--#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
- # include <openssl/rand.h>
-
- /* Suppress compile warning of OpenSSL deprecation (OpenSSL is deprecated
-@@ -1147,7 +1148,8 @@
- key_ok = PJ_TRUE;
-
-
--#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
-
- /* Include OpenSSL libraries for MSVC */
- # ifdef _MSC_VER
-
diff --git a/libraries/pjproject-ring/patches/ice_config.patch b/libraries/pjproject-ring/patches/ice_config.patch
deleted file mode 100644
index 0bc2e43292..0000000000
--- a/libraries/pjproject-ring/patches/ice_config.patch
+++ /dev/null
@@ -1,27 +0,0 @@
---- a/pjnath/include/pjnath/config.h
-+++ b/pjnath/include/pjnath/config.h
-@@ -233,3 +233,3 @@
- #ifndef PJ_ICE_MAX_CAND
--# define PJ_ICE_MAX_CAND 16
-+# define PJ_ICE_MAX_CAND 256
- #endif
-@@ -243,3 +243,3 @@
- #ifndef PJ_ICE_ST_MAX_CAND
--# define PJ_ICE_ST_MAX_CAND 8
-+# define PJ_ICE_ST_MAX_CAND 32
- #endif
-@@ -254,3 +254,3 @@
- #ifndef PJ_ICE_MAX_STUN
--# define PJ_ICE_MAX_STUN 2
-+# define PJ_ICE_MAX_STUN 3
- #endif
-@@ -274,3 +274,3 @@
- #ifndef PJ_ICE_COMP_BITS
--# define PJ_ICE_COMP_BITS 1
-+# define PJ_ICE_COMP_BITS 2
- #endif
-@@ -325,3 +325,3 @@
- #ifndef PJ_ICE_MAX_CHECKS
--# define PJ_ICE_MAX_CHECKS 32
-+# define PJ_ICE_MAX_CHECKS 150
- #endif
diff --git a/libraries/pjproject-ring/patches/intptr_t.patch b/libraries/pjproject-ring/patches/intptr_t.patch
deleted file mode 100644
index 8994a991c0..0000000000
--- a/libraries/pjproject-ring/patches/intptr_t.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- pjproject/pjsip/src/pjsua2/endpoint.cpp.orig 2014-09-05 16:39:29.708512865 -0400
-+++ pjproject/pjsip/src/pjsua2/endpoint.cpp 2014-09-05 16:39:00.084513427 -0400
-@@ -489,7 +489,7 @@
- LogEntry entry;
- entry.level = level;
- entry.msg = string(data, len);
-- entry.threadId = (long)pj_thread_this();
-+ entry.threadId = (intptr_t)pj_thread_this();
- entry.threadName = string(pj_thread_get_name(pj_thread_this()));
-
- ep.utilLogWrite(entry);
diff --git a/libraries/pjproject-ring/patches/ipv6.patch b/libraries/pjproject-ring/patches/ipv6.patch
deleted file mode 100644
index 8b42fbbda1..0000000000
--- a/libraries/pjproject-ring/patches/ipv6.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/pjlib/include/pj/config.h
-+++ b/pjlib/include/pj/config.h
-@@ -549,7 +549,7 @@
- * Default: 0 (disabled, for now)
- */
- #ifndef PJ_HAS_IPV6
--# define PJ_HAS_IPV6 0
-+# define PJ_HAS_IPV6 1
- #endif
-
- /**
diff --git a/libraries/pjproject-ring/patches/isblank.patch b/libraries/pjproject-ring/patches/isblank.patch
deleted file mode 100644
index 98f6f1e827..0000000000
--- a/libraries/pjproject-ring/patches/isblank.patch
+++ /dev/null
@@ -1,8 +0,0 @@
---- pjproject/pjlib/include/pj/compat/ctype.h 2016-10-06 16:39:29.708512865 -0400
-+++ pjproject/pjlib/include/pj/compat/ctype.h 2016-10-06 17:39:00.084513427 -0400
-@@ -43,5 +43,2 @@
-
--#ifndef isblank
--# define isblank(c) (c==' ' || c=='\t')
--#endif
-
diff --git a/libraries/pjproject-ring/patches/multiple_listeners.patch b/libraries/pjproject-ring/patches/multiple_listeners.patch
deleted file mode 100644
index 89590107c8..0000000000
--- a/libraries/pjproject-ring/patches/multiple_listeners.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-diff --git a/pjproject/pjsip/src/pjsip/sip_transport.c b/pjproject_new/pjsip/src/pjsip/sip_transport.c
-index 4b2cc1a..22e3603 100644
---- a/pjsip/src/pjsip/sip_transport.c
-+++ b/pjsip/src/pjsip/sip_transport.c
-@@ -1248,22 +1248,22 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr,
-
- pj_lock_acquire(mgr->lock);
-
-- /* Check that no factory with the same type has been registered. */
-+ /* Check that no factory with the same type and bound address has been registered. */
- status = PJ_SUCCESS;
- for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
-- if (p->type == tpf->type) {
-- status = PJSIP_ETYPEEXISTS;
-- break;
-- }
-- if (p == tpf) {
-- status = PJ_EEXISTS;
-- break;
-- }
-+ if (p->type == tpf->type && !pj_sockaddr_cmp(&tpf->local_addr, &p->local_addr)) {
-+ status = PJSIP_ETYPEEXISTS;
-+ break;
-+ }
-+ if (p == tpf) {
-+ status = PJ_EEXISTS;
-+ break;
-+ }
- }
-
- if (status != PJ_SUCCESS) {
-- pj_lock_release(mgr->lock);
-- return status;
-+ pj_lock_release(mgr->lock);
-+ return status;
- }
-
- pj_list_insert_before(&mgr->factory_list, tpf);
-@@ -2047,13 +2047,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
- pj_memcpy(&key.rem_addr, remote, addr_len);
-
- transport = (pjsip_transport*)
-- pj_hash_get(mgr->table, &key, key_len, NULL);
--
-+ pj_hash_get(mgr->table, &key, key_len, NULL);
-+ unsigned flag = pjsip_transport_get_flag_from_type(type);
- if (transport == NULL) {
-- unsigned flag = pjsip_transport_get_flag_from_type(type);
- const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
-
--
- /* Ignore address for loop transports. */
- if (type == PJSIP_TRANSPORT_LOOP ||
- type == PJSIP_TRANSPORT_LOOP_DGRAM)
-@@ -2135,6 +2135,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
- }
-
- } else {
-+ /* Make sure we don't use another factory than the one given if secure flag is set */
-+ if (flag & PJSIP_TRANSPORT_SECURE) {
-+ TRACE_((THIS_FILE, "Can't create new TLS transport with no provided suitable TLS listener."));
-+ return PJSIP_ETPNOTSUITABLE;
-+ }
-
- /* Find factory with type matches the destination type */
- factory = mgr->factory_list.next;
diff --git a/libraries/pjproject-ring/patches/notestsapps.patch b/libraries/pjproject-ring/patches/notestsapps.patch
deleted file mode 100644
index 8bf957b368..0000000000
--- a/libraries/pjproject-ring/patches/notestsapps.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-diff --git a/Makefile b/Makefile
-index 33a4e6b..a486eb7 100644
---- a/Makefile
-+++ b/Makefile
-@@ -4,7 +4,7 @@ include build/host-$(HOST_NAME).mak
- include version.mak
-
- LIB_DIRS = pjlib/build pjlib-util/build pjnath/build third_party/build pjmedia/build pjsip/build
--DIRS = $(LIB_DIRS) pjsip-apps/build $(EXTRA_DIRS)
-+DIRS = $(LIB_DIRS) $(EXTRA_DIRS)
-
- ifdef MINSIZE
- MAKE_FLAGS := MINSIZE=1
-diff --git a/pjlib-util/build/Makefile b/pjlib-util/build/Makefile
-index cb601cb..862a78a 100644
---- a/pjlib-util/build/Makefile
-+++ b/pjlib-util/build/Makefile
-@@ -54,7 +54,6 @@ export UTIL_TEST_OBJS += xml.o encryption.o stun.o resolver_test.o test.o \
- export UTIL_TEST_CFLAGS += $(_CFLAGS)
- export UTIL_TEST_CXXFLAGS += $(_CXXFLAGS)
- export UTIL_TEST_LDFLAGS += $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
--export UTIL_TEST_EXE:=pjlib-util-test-$(TARGET_NAME)$(HOST_EXE)
-
-
- export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
-diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile
-index 1e64950..a75fa65 100644
---- a/pjlib/build/Makefile
-+++ b/pjlib/build/Makefile
-@@ -56,7 +56,6 @@ export TEST_OBJS += activesock.o atomic.o echo_clt.o errno.o exception.o \
- export TEST_CFLAGS += $(_CFLAGS)
- export TEST_CXXFLAGS += $(_CXXFLAGS)
- export TEST_LDFLAGS += $(PJLIB_LDLIB) $(_LDFLAGS)
--export TEST_EXE := pjlib-test-$(TARGET_NAME)$(HOST_EXE)
-
-
- export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
-diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile
-index 8012cb7..2ca283a 100644
---- a/pjmedia/build/Makefile
-+++ b/pjmedia/build/Makefile
-@@ -165,7 +165,6 @@ export PJMEDIA_TEST_LDFLAGS += $(PJMEDIA_CODEC_LDLIB) \
- $(PJLIB_UTIL_LDLIB) \
- $(PJNATH_LDLIB) \
- $(_LDFLAGS)
--export PJMEDIA_TEST_EXE:=pjmedia-test-$(TARGET_NAME)$(HOST_EXE)
-
-
- export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
-diff --git a/pjnath/build/Makefile b/pjnath/build/Makefile
-index 1bc08b5..109f79b 100644
---- a/pjnath/build/Makefile
-+++ b/pjnath/build/Makefile
-@@ -54,7 +54,6 @@ export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o server.o concur_test.o
- export PJNATH_TEST_CFLAGS += $(_CFLAGS)
- export PJNATH_TEST_CXXFLAGS += $(_CXXFLAGS)
- export PJNATH_TEST_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
--export PJNATH_TEST_EXE:=pjnath-test-$(TARGET_NAME)$(HOST_EXE)
-
-
- ###############################################################################
-@@ -65,7 +64,6 @@ export PJTURN_CLIENT_OBJS += client_main.o
- export PJTURN_CLIENT_CFLAGS += $(_CFLAGS)
- export PJTURN_CLIENT_CXXFLAGS += $(_CXXFLAGS)
- export PJTURN_CLIENT_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
--export PJTURN_CLIENT_EXE:=pjturn-client-$(TARGET_NAME)$(HOST_EXE)
-
- ###############################################################################
- # Defines for building TURN server application
-@@ -76,7 +74,6 @@ export PJTURN_SRV_OBJS += allocation.o auth.o listener_udp.o \
- export PJTURN_SRV_CFLAGS += $(_CFLAGS)
- export PJTURN_SRV_CXXFLAGS += $(_CXXFLAGS)
- export PJTURN_SRV_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
--export PJTURN_SRV_EXE:=pjturn-srv-$(TARGET_NAME)$(HOST_EXE)
-
-
-
-diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
-index d2a5c2a..7e2ec60 100644
---- a/pjsip/build/Makefile
-+++ b/pjsip/build/Makefile
-@@ -140,7 +140,7 @@ export PJSUA2_LIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
- account.o endpoint.o json.o persistent.o types.o \
- siptypes.o call.o presence.o media.o
- export PJSUA2_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
--export PJSUA2_LIB_CXXFLAGS = $(PJSUA2_LIB_CFLAGS)
-+export PJSUA2_LIB_CXXFLAGS = $(_CXXFLAGS) $(PJ_VIDEO_CFLAGS)
- export PJSUA2_LIB_LDFLAGS += $(PJSUA_LIB_LDLIB) \
- $(PJSIP_UA_LDLIB) \
- $(PJSIP_SIMPLE_LDLIB) \
-@@ -165,7 +165,6 @@ export PJSUA2_TEST_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
- export PJSUA2_TEST_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
- export PJSUA2_TEST_CXXFLAGS = $(PJSUA2_LIB_CFLAGS)
- export PJSUA2_TEST_LDFLAGS += $(PJ_LDXXFLAGS) $(PJ_LDXXLIBS) $(LDFLAGS)
--export PJSUA2_TEST_EXE := pjsua2-test-$(TARGET_NAME)$(HOST_EXE)
-
- export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
-
-@@ -195,7 +194,6 @@ export TEST_LDFLAGS += $(PJSIP_LDLIB) \
- $(PJLIB_UTIL_LDLIB) \
- $(PJNATH_LDLIB) \
- $(_LDFLAGS)
--export TEST_EXE := pjsip-test-$(TARGET_NAME)$(HOST_EXE)
-
-
- export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
diff --git a/libraries/pjproject-ring/patches/pj_ice_sess.patch b/libraries/pjproject-ring/patches/pj_ice_sess.patch
deleted file mode 100644
index bd040ffe3e..0000000000
--- a/libraries/pjproject-ring/patches/pj_ice_sess.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/pjnath/include/pjnath/ice_strans.h
-+++ b/pjnath/include/pjnath/ice_strans.h
-@@ -845,6 +845,8 @@ PJ_DECL(pj_status_t) pj_ice_strans_sendt
- int dst_addr_len);
-
-
-+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess(pj_ice_strans *ice_st);
-+
- /**
- * @}
- */
---- a/pjnath/src/pjnath/ice_strans.c
-+++ b/pjnath/src/pjnath/ice_strans.c
-@@ -1243,6 +1243,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto
- return PJ_EINVALIDOP;
- }
-
-+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess( pj_ice_strans *ice_st )
-+{
-+ return ice_st->ice;
-+}
-+
diff --git a/libraries/pjproject-ring/patches/pj_uwp.patch b/libraries/pjproject-ring/patches/pj_uwp.patch
deleted file mode 100644
index 2e7f038266..0000000000
--- a/libraries/pjproject-ring/patches/pj_uwp.patch
+++ /dev/null
@@ -1,203 +0,0 @@
---- a/pjlib-util/build/pjlib_util.vcxproj
-+++ b/pjlib-util/build/pjlib_util.vcxproj
-@@ -327,7 +327,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjlib/build/pjlib.vcxproj
-+++ b/pjlib/build/pjlib.vcxproj
-@@ -327,8 +327,8 @@
- <TargetEnvironment>X64</TargetEnvironment>
- </Midl>
- <ClCompile>
-- <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <AdditionalIncludeDirectories>..\..\..\include;../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>_WIN32_WINNT=0x0A00;PJ_TERM_HAS_COLOR=0;PJ_OS_HAS_CHECK_STACK=0;WIN32_NATIVE;PJ_HAS_SSL_SOCK;PJ_HAS_TLS_SOCK;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- </ItemDefinitionGroup>
-@@ -620,6 +620,7 @@
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="..\src\pj\ip_helper_win32.c">
-+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(API_Family)'!='WinDesktop'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="..\src\pj\ip_helper_generic.c">
-@@ -851,6 +852,7 @@
- <ClCompile Include="..\src\pj\sock_select.c" />
- <ClCompile Include="..\src\pj\ssl_sock_common.c" />
- <ClCompile Include="..\src\pj\ssl_sock_dump.c" />
-+ <ClCompile Include="..\src\pj\ssl_sock_gtls.c" />
- <ClCompile Include="..\src\pj\ssl_sock_ossl.c" />
- <ClCompile Include="..\src\pj\string.c" />
- <ClCompile Include="..\src\pj\symbols.c">
---- a/pjlib/include/pj/compat/string.h
-+++ b/pjlib/include/pj/compat/string.h
-@@ -43,7 +43,7 @@
- # include <stdlib.h>
- #endif
-
--#if defined(_MSC_VER)
-+#if defined(PJ_WIN32)
- # define strcasecmp _stricmp
- # define strncasecmp _strnicmp
- # define snprintf _snprintf
---- /dev/null
-+++ b/pjlib/include/pj/config_site.h
-@@ -0,0 +1,8 @@
-+#include "config_site_sample.h"
-+
-+#undef PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
-+#undef PJMEDIA_AUDIO_DEV_HAS_WMME
-+
-+#define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 0
-+#define PJMEDIA_AUDIO_DEV_HAS_WMME 0
-+#define PJMEDIA_RESAMPLE_IMP PJMEDIA_RESAMPLE_SPEEX
-\ No newline at end of file
---- a/pjlib/src/pj/file_access_win32.c
-+++ b/pjlib/src/pj/file_access_win32.c
-@@ -79,7 +79,7 @@ static HANDLE WINAPI create_file(LPCTSTR filename, DWORD desired_access,
- return CreateFile2(filename, desired_access, share_mode,
- creation_disposition, NULL);
- #else
-- return CreateFile(filename, desired_access, share_mode,
-+ return CreateFile2(filename, desired_access, share_mode,
- security_attributes, creation_disposition,
- flags_and_attributes, template_file);
- #endif
---- a/pjlib/src/pj/file_io_win32.c
-+++ b/pjlib/src/pj/file_io_win32.c
-@@ -129,7 +129,7 @@ PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
- dwDesiredAccess, dwShareMode, dwCreationDisposition,
- NULL);
- #else
-- hFile = CreateFile(PJ_STRING_TO_NATIVE(pathname,
-+ hFile = CreateFile2(PJ_STRING_TO_NATIVE(pathname,
- wpathname, sizeof(wpathname)),
- dwDesiredAccess, dwShareMode, NULL,
- dwCreationDisposition, dwFlagsAndAttributes, NULL);
---- a/pjmedia/build/pjmedia.vcxproj
-+++ b/pjmedia/build/pjmedia.vcxproj
-@@ -325,7 +325,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- </ItemDefinitionGroup>
---- a/pjnath/build/pjnath.vcxproj
-+++ b/pjnath/build/pjnath.vcxproj
-@@ -410,7 +410,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- </ItemDefinitionGroup>
---- a/pjsip/build/pjsip_core.vcxproj
-+++ b/pjsip/build/pjsip_core.vcxproj
-@@ -327,7 +327,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;PJ_HAS_SSL_SOCK;_LIB;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjsip/build/pjsip_simple.vcxproj
-+++ b/pjsip/build/pjsip_simple.vcxproj
-@@ -362,7 +362,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib-util/include;../../pjlib/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjsip/build/pjsip_ua.vcxproj
-+++ b/pjsip/build/pjsip_ua.vcxproj
-@@ -327,7 +327,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjmedia/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjsip/build/pjsua2_lib.vcxproj
-+++ b/pjsip/build/pjsua2_lib.vcxproj
-@@ -364,7 +364,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjmedia/include;../../pjlib-util/include;../../pjlib/include;../../pjnath/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjsip/build/pjsua_lib.vcxproj
-+++ b/pjsip/build/pjsua_lib.vcxproj
-@@ -362,7 +362,7 @@
- </Midl>
- <ClCompile>
- <AdditionalIncludeDirectories>../include;../../pjmedia/include;../../pjlib-util/include;../../pjlib/include;../../pjnath/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-- <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <PreprocessorDefinitions>PJ_OS_HAS_CHECK_STACK=0;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PrecompiledHeaderOutputFile />
- </ClCompile>
- <Lib>
---- a/pjsip/src/pjsip/sip_dialog.c
-+++ b/pjsip/src/pjsip/sip_dialog.c
-@@ -882,7 +882,7 @@ PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg)
- PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_inc_lock(), sess_count=%d",
- dlg->sess_count));
-
-- pj_mutex_lock(dlg->mutex_);
-+ pj_mutex_trylock(dlg->mutex_);
- dlg->sess_count++;
-
- PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_inc_lock(), sess_count=%d",
---- a/pjlib/build/pjlib.vcxproj
-+++ b/pjlib/build/pjlib.vcxproj
-@@ -617,7 +617,7 @@
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Static|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
-- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
-+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="..\src\pj\ip_helper_win32.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
---- a/pjlib/src/pj/os_core_win32.c
-+++ b/pjlib/src/pj/os_core_win32.c
-@@ -1424,10 +1424,10 @@ PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
-
- PJ_LOG(6, (event->obj_name, "Pulsing event"));
-
-- if (PulseEvent(event->hEvent))
-+ //if (PulseEvent(event->hEvent))
- return PJ_SUCCESS;
-- else
-- return PJ_RETURN_OS_ERROR(GetLastError());
-+ //else
-+ //return PJ_RETURN_OS_ERROR(GetLastError());
- #endif
- }
-
---
-2.10.2.windows.1
-
diff --git a/libraries/pjproject-ring/patches/pj_uwp_fix_turn_fallback.patch b/libraries/pjproject-ring/patches/pj_uwp_fix_turn_fallback.patch
deleted file mode 100644
index 5d7b44b9f5..0000000000
--- a/libraries/pjproject-ring/patches/pj_uwp_fix_turn_fallback.patch
+++ /dev/null
@@ -1,51 +0,0 @@
---- a/pjnath/src/pjnath/turn_session.c
-+++ b/pjnath/src/pjnath/turn_session.c
-@@ -653,3 +653,3 @@
-
-- cnt = PJ_TURN_MAX_DNS_SRV_CNT;
-+ cnt = 1;
- ai = (pj_addrinfo*)
---- a/pjnath/src/pjnath/ice_strans.c
-+++ b/pjnath/src/pjnath/ice_strans.c
-@@ -2078,6 +2078,38 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
- }
-
- sess_init_update(comp->ice_st);
-+ } else if ((old_state == PJ_TURN_STATE_RESOLVING || old_state == PJ_TURN_STATE_ALLOCATING) &&
-+ new_state >= PJ_TURN_STATE_DEALLOCATING)
-+ {
-+ pj_ice_sess_cand *cand = NULL;
-+ unsigned i;
-+
-+ /* DNS resolution has failed! */
-+ ++comp->turn[tp_idx].err_cnt;
-+
-+ /* Unregister ourself from the TURN relay */
-+ pj_turn_sock_set_user_data(turn_sock, NULL);
-+ comp->turn[tp_idx].sock = NULL;
-+
-+ /* Wait until initialization completes */
-+ pj_grp_lock_acquire(comp->ice_st->grp_lock);
-+
-+ /* Find relayed candidate in the component */
-+ for (i=0; i<comp->cand_cnt; ++i) {
-+ if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
-+ comp->cand_list[i].transport_id == data->transport_id)
-+ {
-+ cand = &comp->cand_list[i];
-+ break;
-+ }
-+ }
-+ pj_assert(cand != NULL);
-+
-+ pj_grp_lock_release(comp->ice_st->grp_lock);
-+
-+ cand->status = old_state == PJ_TURN_STATE_RESOLVING ? PJ_ERESOLVE : PJ_EINVALIDOP;
-+
-+ sess_init_update(comp->ice_st);
-
- } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
- pj_turn_session_info info;
---
-2.8.1.windows.1
-
diff --git a/libraries/pjproject-ring/patches/pj_uwp_gnutls.patch b/libraries/pjproject-ring/patches/pj_uwp_gnutls.patch
deleted file mode 100644
index 9f20025be4..0000000000
--- a/libraries/pjproject-ring/patches/pj_uwp_gnutls.patch
+++ /dev/null
@@ -1,3004 +0,0 @@
-Copyright (c) 2014-2017 Savoir-faire Linux Inc.
-
-ssl_sock: add gnutls backend
-
-This backend is mutually exclusive with the OpenSSL one, but completely
-compatible, and conformant to the PJSIP API. Also avoids any license issues
-when linking statically.
-
-The configure script is updated to select either OpenSSL or GnuTLS
-with --enable-ssl[='...'] and a new symbol (PJ_HAS_TLS_SOCK) is introduced
-to identify which backend is in use.
-
-Written by
-Vittorio Giovara <vittorio.giovara@savoirfairelinux.com>
-Philippe Proulx <philippe.proulx@savoirfairelinux.com> and
-Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
-on behalf of Savoir-faire Linux.
---- a/pjlib/include/pj/compat/os_auto.h.in
-+++ b/pjlib/include/pj/compat/os_auto.h.in
-@@ -209,6 +209,9 @@
- #ifndef PJ_HAS_SSL_SOCK
- #undef PJ_HAS_SSL_SOCK
- #endif
-+#ifndef PJ_HAS_TLS_SOCK
-+#undef PJ_HAS_TLS_SOCK
-+#endif
-
-
- #endif /* __PJ_COMPAT_OS_AUTO_H__ */
---- a/pjlib/include/pj/config.h
-+++ b/pjlib/include/pj/config.h
-@@ -855,13 +861,15 @@
-
- /**
- * Enable secure socket. For most platforms, this is implemented using
-- * OpenSSL, so this will require OpenSSL to be installed. For Symbian
-+ * OpenSSL, so this will require OpenSSL or GnuTLS to be installed. For Symbian
- * platform, this is implemented natively using CSecureSocket.
- *
- * Default: 0 (for now)
- */
- #ifndef PJ_HAS_SSL_SOCK
- # define PJ_HAS_SSL_SOCK 0
-+ // When set to 1 secure sockets will use the GnuTLS backend
-+# define PJ_HAS_TLS_SOCK 0
- #endif
-
-
---- a/pjlib/include/pj/ssl_sock.h
-+++ b/pjlib/include/pj/ssl_sock.h
-@@ -184,6 +184,11 @@ typedef struct pj_ssl_cert_info {
- pj_str_t raw; /**< Raw certificate in PEM format, only
- available for remote certificate. */
-
-+ struct {
-+ unsigned cnt; /**< # of entry */
-+ pj_str_t* cert_raw;
-+ } raw_chain;
-+
- } pj_ssl_cert_info;
-
-
---- a/pjlib/src/pj/ssl_sock_common.c
-+++ b/pjlib/src/pj/ssl_sock_common.c
-@@ -35,7 +35,12 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
- param->async_cnt = 1;
- param->concurrency = -1;
- param->whole_data = PJ_TRUE;
-+#if defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 1
-+ // GnuTLS is allowed to send bigger chunks
-+ param->send_buffer_size = 65536;
-+#else
- param->send_buffer_size = 8192;
-+#endif
- #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0
- param->read_buffer_size = 1500;
- #endif
---- /dev/null
-+++ b/pjlib/src/pj/ssl_sock_gtls.c
-@@ -0,0 +1,2887 @@
-+/* $Id$ */
-+/*
-+ * Copyright (C) 2014-2016 Savoir-faire Linux. (https://www.savoirfairelinux.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/ssl_sock.h>
-+#include <pj/activesock.h>
-+#include <pj/compat/socket.h>
-+#include <pj/assert.h>
-+#include <pj/errno.h>
-+#include <pj/list.h>
-+#include <pj/lock.h>
-+#include <pj/log.h>
-+#include <pj/math.h>
-+#include <pj/os.h>
-+#include <pj/pool.h>
-+#include <pj/string.h>
-+#include <pj/timer.h>
-+#include <pj/file_io.h>
-+
-+#if GNUTLS_VERSION_NUMBER < 0x030306 && !defined(_MSC_VER)
-+#include <dirent.h>
-+#endif
-+
-+#include <errno.h>
-+
-+/* Only build when PJ_HAS_SSL_SOCK and PJ_HAS_TLS_SOCK are enabled */
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK != 0
-+
-+#define THIS_FILE "ssl_sock_gtls.c"
-+
-+/* Workaround for ticket #985 */
-+#define DELAYED_CLOSE_TIMEOUT 200
-+
-+/* Maximum ciphers */
-+#define MAX_CIPHERS 100
-+
-+/* Standard trust locations */
-+#define TRUST_STORE_FILE1 "/etc/ssl/certs/ca-certificates.crt"
-+#define TRUST_STORE_FILE2 "/etc/ssl/certs/ca-bundle.crt"
-+
-+/* Debugging output level for GnuTLS only */
-+#define GNUTLS_LOG_LEVEL 0
-+
-+/* GnuTLS includes */
-+#include <gnutls/gnutls.h>
-+#include <gnutls/x509.h>
-+#include <gnutls/abstract.h>
-+
-+#ifdef _MSC_VER
-+# pragma comment( lib, "libgnutls")
-+#endif
-+
-+
-+/* TLS state enumeration. */
-+enum tls_connection_state {
-+ TLS_STATE_NULL,
-+ TLS_STATE_HANDSHAKING,
-+ TLS_STATE_ESTABLISHED
-+};
-+
-+/* Internal timer types. */
-+enum timer_id {
-+ TIMER_NONE,
-+ TIMER_HANDSHAKE_TIMEOUT,
-+ TIMER_CLOSE
-+};
-+
-+/* Structure of SSL socket read buffer. */
-+typedef struct read_data_t {
-+ void *data;
-+ pj_size_t len;
-+} read_data_t;
-+
-+/*
-+ * Get the offset of pointer to read-buffer of SSL socket from read-buffer
-+ * of active socket. Note that both SSL socket and active socket employ
-+ * different but correlated read-buffers (as much as async_cnt for each),
-+ * and to make it easier/faster to find corresponding SSL socket's read-buffer
-+ * from known active socket's read-buffer, the pointer of corresponding
-+ * SSL socket's read-buffer is stored right after the end of active socket's
-+ * read-buffer.
-+ */
-+#define OFFSET_OF_READ_DATA_PTR(ssock, asock_rbuf) \
-+ (read_data_t**) \
-+ ((pj_int8_t *)(asock_rbuf) + \
-+ ssock->param.read_buffer_size)
-+
-+/* Structure of SSL socket write data. */
-+typedef struct write_data_t {
-+ PJ_DECL_LIST_MEMBER(struct write_data_t);
-+ pj_ioqueue_op_key_t key;
-+ pj_size_t record_len;
-+ pj_ioqueue_op_key_t *app_key;
-+ pj_size_t plain_data_len;
-+ pj_size_t data_len;
-+ unsigned flags;
-+ union {
-+ char content[1];
-+ const char *ptr;
-+ } data;
-+} write_data_t;
-+
-+
-+/* Structure of SSL socket write buffer (circular buffer). */
-+typedef struct send_buf_t {
-+ char *buf;
-+ pj_size_t max_len;
-+ char *start;
-+ pj_size_t len;
-+} send_buf_t;
-+
-+
-+/* Circular buffer object */
-+typedef struct circ_buf_t {
-+ pj_size_t cap; /* maximum number of elements (must be power of 2) */
-+ pj_size_t readp; /* index of oldest element */
-+ pj_size_t writep; /* index at which to write new element */
-+ pj_size_t size; /* number of elements */
-+ pj_uint8_t *buf; /* data buffer */
-+ pj_pool_t *pool; /* where new allocations will take place */
-+} circ_buf_t;
-+
-+
-+/* Secure socket structure definition. */
-+struct pj_ssl_sock_t {
-+ pj_pool_t *pool;
-+ pj_ssl_sock_t *parent;
-+ pj_ssl_sock_param param;
-+ pj_ssl_sock_param newsock_param;
-+ pj_ssl_cert_t *cert;
-+
-+ pj_ssl_cert_info local_cert_info;
-+ pj_ssl_cert_info remote_cert_info;
-+
-+ pj_bool_t is_server;
-+ enum tls_connection_state connection_state;
-+ pj_ioqueue_op_key_t handshake_op_key;
-+ pj_timer_entry timer;
-+ pj_status_t verify_status;
-+
-+ int last_err;
-+
-+ pj_sock_t sock;
-+ pj_activesock_t *asock;
-+
-+ pj_sockaddr local_addr;
-+ pj_sockaddr rem_addr;
-+ int addr_len;
-+
-+ pj_bool_t read_started;
-+ pj_size_t read_size;
-+ pj_uint32_t read_flags;
-+ void **asock_rbuf;
-+ read_data_t *ssock_rbuf;
-+
-+ write_data_t write_pending; /* list of pending writes */
-+ write_data_t write_pending_empty; /* cache for write_pending */
-+ pj_bool_t flushing_write_pend; /* flag of flushing is ongoing */
-+ send_buf_t send_buf;
-+ write_data_t send_pending; /* list of pending write to network */
-+
-+ gnutls_session_t session;
-+ gnutls_certificate_credentials_t xcred;
-+
-+ circ_buf_t circ_buf_input;
-+ pj_lock_t *circ_buf_input_mutex;
-+
-+ circ_buf_t circ_buf_output;
-+ pj_lock_t *circ_buf_output_mutex;
-+
-+ int tls_init_count; /* library initialization counter */
-+};
-+
-+
-+/* Certificate/credential structure definition. */
-+struct pj_ssl_cert_t {
-+ pj_str_t CA_file;
-+ pj_str_t CA_path;
-+ pj_str_t cert_file;
-+ pj_str_t privkey_file;
-+ pj_str_t privkey_pass;
-+};
-+
-+/* GnuTLS available ciphers */
-+static unsigned tls_available_ciphers;
-+
-+/* Array of id/names for available ciphers */
-+static struct tls_ciphers_t {
-+ pj_ssl_cipher id;
-+ const char *name;
-+} tls_ciphers[MAX_CIPHERS];
-+
-+/* Last error reported somehow */
-+static int tls_last_error;
-+
-+
-+/*
-+ *******************************************************************
-+ * Circular buffer functions.
-+ *******************************************************************
-+ */
-+
-+static pj_status_t circ_init(pj_pool_factory *factory,
-+ circ_buf_t *cb, pj_size_t cap)
-+{
-+ cb->cap = cap;
-+ cb->readp = 0;
-+ cb->writep = 0;
-+ cb->size = 0;
-+
-+ /* Initial pool holding the buffer elements */
-+ cb->pool = pj_pool_create(factory, "tls-circ%p", cap, cap, NULL);
-+ if (!cb->pool)
-+ return PJ_ENOMEM;
-+
-+ /* Allocate circular buffer */
-+ cb->buf = pj_pool_alloc(cb->pool, cap);
-+ if (!cb->buf) {
-+ pj_pool_release(cb->pool);
-+ return PJ_ENOMEM;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+static void circ_deinit(circ_buf_t *cb)
-+{
-+ if (cb->pool) {
-+ pj_pool_release(cb->pool);
-+ cb->pool = NULL;
-+ }
-+}
-+
-+static pj_bool_t circ_empty(const circ_buf_t *cb)
-+{
-+ return cb->size == 0;
-+}
-+
-+static pj_size_t circ_size(const circ_buf_t *cb)
-+{
-+ return cb->size;
-+}
-+
-+static pj_size_t circ_avail(const circ_buf_t *cb)
-+{
-+ return cb->cap - cb->size;
-+}
-+
-+static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
-+{
-+ pj_size_t size_after = cb->cap - cb->readp;
-+ pj_size_t tbc = PJ_MIN(size_after, len);
-+ pj_size_t rem = len - tbc;
-+
-+ pj_memcpy(dst, cb->buf + cb->readp, tbc);
-+ pj_memcpy(dst + tbc, cb->buf, rem);
-+
-+ cb->readp += len;
-+ cb->readp &= (cb->cap - 1);
-+
-+ cb->size -= len;
-+}
-+
-+static pj_status_t circ_write(circ_buf_t *cb,
-+ const pj_uint8_t *src, pj_size_t len)
-+{
-+ /* Overflow condition: resize */
-+ if (len > circ_avail(cb)) {
-+ /* Minimum required capacity */
-+ pj_size_t min_cap = len + cb->size;
-+
-+ /* Next 32-bit power of two */
-+ min_cap--;
-+ min_cap |= min_cap >> 1;
-+ min_cap |= min_cap >> 2;
-+ min_cap |= min_cap >> 4;
-+ min_cap |= min_cap >> 8;
-+ min_cap |= min_cap >> 16;
-+ min_cap++;
-+
-+ /* Create a new pool to hold a bigger buffer, using the same factory */
-+ pj_pool_t *pool = pj_pool_create(cb->pool->factory, "tls-circ%p",
-+ min_cap, min_cap, NULL);
-+ if (!pool)
-+ return PJ_ENOMEM;
-+
-+ /* Allocate our new buffer */
-+ pj_uint8_t *buf = pj_pool_alloc(pool, min_cap);
-+ if (!buf) {
-+ pj_pool_release(pool);
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Save old size, which we shall restore after the next read */
-+ pj_size_t old_size = cb->size;
-+
-+ /* Copy old data into beginning of new buffer */
-+ circ_read(cb, buf, cb->size);
-+
-+ /* Restore old size now */
-+ cb->size = old_size;
-+
-+ /* Release the previous pool */
-+ pj_pool_release(cb->pool);
-+
-+ /* Update circular buffer members */
-+ cb->pool = pool;
-+ cb->buf = buf;
-+ cb->readp = 0;
-+ cb->writep = cb->size;
-+ cb->cap = min_cap;
-+ }
-+
-+ pj_size_t size_after = cb->cap - cb->writep;
-+ pj_size_t tbc = PJ_MIN(size_after, len);
-+ pj_size_t rem = len - tbc;
-+
-+ pj_memcpy(cb->buf + cb->writep, src, tbc);
-+ pj_memcpy(cb->buf, src + tbc, rem);
-+
-+ cb->writep += len;
-+ cb->writep &= (cb->cap - 1);
-+
-+ cb->size += len;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ *******************************************************************
-+ * Static/internal functions.
-+ *******************************************************************
-+ */
-+
-+/* Convert from GnuTLS error to pj_status_t. */
-+static pj_status_t tls_status_from_err(pj_ssl_sock_t *ssock, int err)
-+{
-+ pj_status_t status;
-+
-+ switch (err) {
-+ case GNUTLS_E_SUCCESS:
-+ status = PJ_SUCCESS;
-+ break;
-+ case GNUTLS_E_MEMORY_ERROR:
-+ status = PJ_ENOMEM;
-+ break;
-+ case GNUTLS_E_LARGE_PACKET:
-+ status = PJ_ETOOBIG;
-+ break;
-+ case GNUTLS_E_NO_CERTIFICATE_FOUND:
-+ status = PJ_ENOTFOUND;
-+ break;
-+ case GNUTLS_E_SESSION_EOF:
-+ status = PJ_EEOF;
-+ break;
-+ case GNUTLS_E_HANDSHAKE_TOO_LARGE:
-+ status = PJ_ETOOBIG;
-+ break;
-+ case GNUTLS_E_EXPIRED:
-+ status = PJ_EGONE;
-+ break;
-+ case GNUTLS_E_TIMEDOUT:
-+ status = PJ_ETIMEDOUT;
-+ break;
-+ case GNUTLS_E_PREMATURE_TERMINATION:
-+ status = PJ_ECANCELLED;
-+ break;
-+ case GNUTLS_E_INTERNAL_ERROR:
-+ case GNUTLS_E_UNIMPLEMENTED_FEATURE:
-+ status = PJ_EBUG;
-+ break;
-+ case GNUTLS_E_AGAIN:
-+ case GNUTLS_E_INTERRUPTED:
-+ case GNUTLS_E_REHANDSHAKE:
-+ status = PJ_EPENDING;
-+ break;
-+ case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
-+ case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
-+ case GNUTLS_E_RECORD_LIMIT_REACHED:
-+ status = PJ_ETOOMANY;
-+ break;
-+ case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
-+ case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
-+ case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
-+ case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
-+ case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
-+ case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
-+ status = PJ_ENOTSUP;
-+ break;
-+ case GNUTLS_E_INVALID_SESSION:
-+ case GNUTLS_E_INVALID_REQUEST:
-+ case GNUTLS_E_INVALID_PASSWORD:
-+ case GNUTLS_E_ILLEGAL_PARAMETER:
-+ case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
-+ case GNUTLS_E_UNEXPECTED_PACKET:
-+ case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
-+ case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
-+ case GNUTLS_E_UNWANTED_ALGORITHM:
-+ case GNUTLS_E_USER_ERROR:
-+ status = PJ_EINVAL;
-+ break;
-+ default:
-+ status = PJ_EUNKNOWN;
-+ break;
-+ }
-+
-+ /* Not thread safe */
-+ tls_last_error = err;
-+ if (ssock)
-+ ssock->last_err = err;
-+ return status;
-+}
-+
-+
-+/* Get error string from GnuTLS using tls_last_error */
-+static pj_str_t tls_strerror(pj_status_t status,
-+ char *buf, pj_size_t bufsize)
-+{
-+ pj_str_t errstr;
-+ const char *tmp = gnutls_strerror(tls_last_error);
-+
-+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
-+ if (tmp) {
-+ pj_ansi_strncpy(buf, tmp, bufsize);
-+ errstr = pj_str(buf);
-+ return errstr;
-+ }
-+#endif /* PJ_HAS_ERROR_STRING */
-+
-+ errstr.ptr = buf;
-+ errstr.slen = pj_ansi_snprintf(buf, bufsize, "GnuTLS error %d: %s",
-+ tls_last_error, tmp);
-+ if (errstr.slen < 1 || errstr.slen >= (int) bufsize)
-+ errstr.slen = bufsize - 1;
-+
-+ return errstr;
-+}
-+
-+
-+/* GnuTLS way of reporting internal operations. */
-+static void tls_print_logs(int level, const char* msg)
-+{
-+ PJ_LOG(3, (THIS_FILE, "GnuTLS [%d]: %s", level, msg));
-+}
-+
-+
-+/* Initialize GnuTLS. */
-+static pj_status_t tls_init(void)
-+{
-+ /* Register error subsystem */
-+ pj_status_t status = pj_register_strerror(PJ_ERRNO_START_USER +
-+ PJ_ERRNO_SPACE_SIZE * 6,
-+ PJ_ERRNO_SPACE_SIZE,
-+ &tls_strerror);
-+ pj_assert(status == PJ_SUCCESS);
-+
-+ /* Init GnuTLS library */
-+ int ret = gnutls_global_init();
-+ if (ret < 0)
-+ return tls_status_from_err(NULL, ret);
-+
-+ gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
-+ gnutls_global_set_log_function(tls_print_logs);
-+
-+ /* Init available ciphers */
-+ if (!tls_available_ciphers) {
-+ unsigned int i;
-+
-+ for (i = 0; ; i++) {
-+ unsigned char id[2];
-+ const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
-+ NULL, NULL, NULL, NULL);
-+ tls_ciphers[i].id = 0;
-+ /* usually the array size is bigger than the number of available
-+ * ciphers anyway, so by checking here we can exit the loop as soon
-+ * as either all ciphers have been added or the array is full */
-+ if (suite && i < PJ_ARRAY_SIZE(tls_ciphers)) {
-+ tls_ciphers[i].id = (pj_ssl_cipher)
-+ (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ tls_ciphers[i].name = suite;
-+ } else
-+ break;
-+ }
-+
-+ tls_available_ciphers = i;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Shutdown GnuTLS */
-+static void tls_deinit(void)
-+{
-+ gnutls_global_deinit();
-+}
-+
-+
-+/* Callback invoked every time a certificate has to be validated. */
-+static int tls_cert_verify_cb(gnutls_session_t session)
-+{
-+ pj_ssl_sock_t *ssock;
-+ unsigned int status;
-+ int ret;
-+
-+ /* Get SSL socket instance */
-+ ssock = (pj_ssl_sock_t *)gnutls_session_get_ptr(session);
-+ pj_assert(ssock);
-+
-+ /* Support only x509 format */
-+ ret = gnutls_certificate_type_get(session) != GNUTLS_CRT_X509;
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ /* Store verification status */
-+ ret = gnutls_certificate_verify_peers2(session, &status);
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+ if (ssock->param.verify_peer) {
-+ if (status & GNUTLS_CERT_INVALID) {
-+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-+ ssock->verify_status |= PJ_SSL_CERT_EISSUER_NOT_FOUND;
-+ else if (status & GNUTLS_CERT_EXPIRED ||
-+ status & GNUTLS_CERT_NOT_ACTIVATED)
-+ ssock->verify_status |= PJ_SSL_CERT_EVALIDITY_PERIOD;
-+ else if (status & GNUTLS_CERT_SIGNER_NOT_CA ||
-+ status & GNUTLS_CERT_INSECURE_ALGORITHM)
-+ ssock->verify_status |= PJ_SSL_CERT_EUNTRUSTED;
-+ else if (status & GNUTLS_CERT_UNEXPECTED_OWNER ||
-+ status & GNUTLS_CERT_MISMATCH)
-+ ssock->verify_status |= PJ_SSL_CERT_EISSUER_MISMATCH;
-+ else if (status & GNUTLS_CERT_REVOKED)
-+ ssock->verify_status |= PJ_SSL_CERT_EREVOKED;
-+ else
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ /* When verification is not requested just return ok here, however
-+ * applications can still get the verification status. */
-+ gnutls_x509_crt_t cert;
-+ unsigned int cert_list_size;
-+ const gnutls_datum_t *cert_list;
-+ int ret;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto out;
-+
-+ cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
-+ if (cert_list == NULL) {
-+ ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
-+ goto out;
-+ }
-+
-+ /* TODO: verify whole chain perhaps? */
-+ ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, &cert_list[0],
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0) {
-+ ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
-+ goto out;
-+ }
-+ ret = gnutls_x509_crt_check_hostname(cert, ssock->param.server_name.ptr);
-+ if (ret < 0)
-+ goto out;
-+
-+ gnutls_x509_crt_deinit(cert);
-+
-+ /* notify GnuTLS to continue handshake normally */
-+ return GNUTLS_E_SUCCESS;
-+
-+out:
-+ tls_last_error = ret;
-+ ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
-+ return GNUTLS_E_CERTIFICATE_ERROR;
-+ }
-+
-+ return GNUTLS_E_SUCCESS;
-+}
-+
-+
-+/* gnutls_handshake() and gnutls_record_send() will call this function to
-+ * send/write (encrypted) data */
-+static ssize_t tls_data_push(gnutls_transport_ptr_t ptr,
-+ const void *data, size_t len)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ if (circ_write(&ssock->circ_buf_output, data, len) != PJ_SUCCESS) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ gnutls_transport_set_errno(ssock->session, ENOMEM);
-+ return -1;
-+ }
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return len;
-+}
-+
-+
-+/* gnutls_handshake() and gnutls_record_recv() will call this function to
-+ * receive/read (encrypted) data */
-+static ssize_t tls_data_pull(gnutls_transport_ptr_t ptr,
-+ void *data, pj_size_t len)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
-+
-+ pj_lock_acquire(ssock->circ_buf_input_mutex);
-+
-+ if (circ_empty(&ssock->circ_buf_input)) {
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+
-+ /* Data buffers not yet filled */
-+ gnutls_transport_set_errno(ssock->session, EAGAIN);
-+ return -1;
-+ }
-+
-+ pj_size_t circ_buf_size = circ_size(&ssock->circ_buf_input);
-+ pj_size_t read_size = PJ_MIN(circ_buf_size, len);
-+
-+ circ_read(&ssock->circ_buf_input, data, read_size);
-+
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+
-+ return read_size;
-+}
-+
-+
-+/* Append a string to the priority string, only once. */
-+static pj_status_t tls_str_append_once(pj_str_t *dst, pj_str_t *src)
-+{
-+ if (pj_strstr(dst, src) == NULL) {
-+ /* Check buffer size */
-+ if (dst->slen + src->slen + 3 > 1024)
-+ return PJ_ETOOMANY;
-+
-+ pj_strcat2(dst, ":+");
-+ pj_strcat(dst, src);
-+ }
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Generate priority string with user preference order. */
-+static pj_status_t tls_priorities_set(pj_ssl_sock_t *ssock)
-+{
-+ char buf[1024];
-+ char priority_buf[256];
-+ pj_str_t cipher_list;
-+ pj_str_t compression = pj_str("COMP-NULL");
-+ pj_str_t server = pj_str(":%SERVER_PRECEDENCE");
-+ int i, j, ret;
-+ pj_str_t priority;
-+ const char *err;
-+
-+ pj_strset(&cipher_list, buf, 0);
-+ pj_strset(&priority, priority_buf, 0);
-+
-+ /* For each level, enable only the requested protocol */
-+ pj_strcat2(&priority, "NORMAL:");
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_2) {
-+ pj_strcat2(&priority, "+VERS-TLS1.2:");
-+ }
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_1) {
-+ pj_strcat2(&priority, "+VERS-TLS1.1:");
-+ }
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1) {
-+ pj_strcat2(&priority, "+VERS-TLS1.0:");
-+ }
-+ pj_strcat2(&priority, "-VERS-SSL3.0:");
-+ pj_strcat2(&priority, "%LATEST_RECORD_VERSION");
-+
-+ pj_strcat(&cipher_list, &priority);
-+ for (i = 0; i < ssock->param.ciphers_num; i++) {
-+ for (j = 0; ; j++) {
-+ pj_ssl_cipher c;
-+ const char *suite;
-+ unsigned char id[2];
-+ gnutls_protocol_t proto;
-+ gnutls_kx_algorithm_t kx;
-+ gnutls_mac_algorithm_t mac;
-+ gnutls_cipher_algorithm_t algo;
-+
-+ suite = gnutls_cipher_suite_info(j, (unsigned char *)id,
-+ &kx, &algo, &mac, &proto);
-+ if (!suite)
-+ break;
-+
-+ c = (pj_ssl_cipher) (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ if (ssock->param.ciphers[i] == c) {
-+ char temp[256];
-+ pj_str_t cipher_entry;
-+
-+ /* Protocol version */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, "VERS-");
-+ pj_strcat2(&cipher_entry, gnutls_protocol_get_name(proto));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Cipher */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_cipher_get_name(algo));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Mac */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_mac_get_name(mac));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Key exchange */
-+ pj_strset(&cipher_entry, temp, 0);
-+ pj_strcat2(&cipher_entry, gnutls_kx_get_name(kx));
-+ ret = tls_str_append_once(&cipher_list, &cipher_entry);
-+ if (ret != PJ_SUCCESS)
-+ return ret;
-+
-+ /* Compression is always disabled */
-+ /* Signature is level-default */
-+ break;
-+ }
-+ }
-+ }
-+
-+ /* Disable compression, it's a TLS-only extension after all */
-+ tls_str_append_once(&cipher_list, &compression);
-+
-+ /* Server will be the one deciding which crypto to use */
-+ if (ssock->is_server) {
-+ if (cipher_list.slen + server.slen + 1 > sizeof(buf))
-+ return PJ_ETOOMANY;
-+ else
-+ pj_strcat(&cipher_list, &server);
-+ }
-+
-+ /* End the string and print it */
-+ cipher_list.ptr[cipher_list.slen] = '\0';
-+ PJ_LOG(5, (ssock->pool->obj_name, "Priority string: %s", cipher_list.ptr));
-+
-+ /* Set our priority string */
-+ ret = gnutls_priority_set_direct(ssock->session,
-+ cipher_list.ptr, &err);
-+ if (ret < 0) {
-+ tls_last_error = GNUTLS_E_INVALID_REQUEST;
-+ return PJ_EINVAL;
-+ }
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Load root CA file or load the installed ones. */
-+static pj_status_t tls_trust_set(pj_ssl_sock_t *ssock)
-+{
-+ int ntrusts = 0;
-+ int err;
-+
-+ err = gnutls_certificate_set_x509_system_trust(ssock->xcred);
-+ if (err > 0)
-+ ntrusts += err;
-+ err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ TRUST_STORE_FILE1,
-+ GNUTLS_X509_FMT_PEM);
-+ if (err > 0)
-+ ntrusts += err;
-+
-+ err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ TRUST_STORE_FILE2,
-+ GNUTLS_X509_FMT_PEM);
-+ if (err > 0)
-+ ntrusts += err;
-+
-+ if (ntrusts > 0)
-+ return PJ_SUCCESS;
-+ else if (!ntrusts)
-+ return PJ_ENOTFOUND;
-+ else
-+ return PJ_EINVAL;
-+}
-+
-+#if GNUTLS_VERSION_NUMBER < 0x030306
-+
-+#ifdef _POSIX_PATH_MAX
-+# define GNUTLS_PATH_MAX _POSIX_PATH_MAX
-+#else
-+# define GNUTLS_PATH_MAX 256
-+#endif
-+
-+static
-+int gnutls_certificate_set_x509_trust_dir(gnutls_certificate_credentials_t cred, const char *dirname, unsigned type)
-+{
-+ DIR *dirp;
-+ struct dirent *d;
-+ int ret;
-+ int r = 0;
-+ char path[GNUTLS_PATH_MAX];
-+#ifndef _WIN32
-+ struct dirent e;
-+#endif
-+
-+ dirp = opendir(dirname);
-+ if (dirp != NULL) {
-+ do {
-+#ifdef _WIN32
-+ d = readdir(dirp);
-+ if (d != NULL) {
-+#else
-+ ret = readdir_r(dirp, &e, &d);
-+ if (ret == 0 && d != NULL
-+#ifdef _DIRENT_HAVE_D_TYPE
-+ && (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
-+#endif
-+ ) {
-+#endif
-+ snprintf(path, sizeof(path), "%s/%s",
-+ dirname, d->d_name);
-+
-+ ret = gnutls_certificate_set_x509_trust_file(cred, path, type);
-+ if (ret >= 0)
-+ r += ret;
-+ }
-+ }
-+ while (d != NULL);
-+ closedir(dirp);
-+ }
-+
-+ return r;
-+}
-+
-+#endif
-+
-+/* Create and initialize new GnuTLS context and instance */
-+static pj_status_t tls_open(pj_ssl_sock_t *ssock)
-+{
-+ pj_ssl_cert_t *cert;
-+ pj_status_t status;
-+ int ret;
-+
-+ pj_assert(ssock);
-+
-+ cert = ssock->cert;
-+
-+ /* Even if reopening is harmless, having one instance only simplifies
-+ * deallocating it later on */
-+ if (!ssock->tls_init_count) {
-+ ssock->tls_init_count++;
-+ ret = tls_init();
-+ if (ret < 0)
-+ return ret;
-+ } else
-+ return PJ_SUCCESS;
-+
-+ /* Start this socket session */
-+ ret = gnutls_init(&ssock->session, ssock->is_server ? GNUTLS_SERVER
-+ : GNUTLS_CLIENT);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Set the ssock object to be retrieved by transport (send/recv) and by
-+ * user data from this session */
-+ gnutls_transport_set_ptr(ssock->session,
-+ (gnutls_transport_ptr_t) (uintptr_t) ssock);
-+ gnutls_session_set_ptr(ssock->session,
-+ (gnutls_transport_ptr_t) (uintptr_t) ssock);
-+
-+ /* Initialize input circular buffer */
-+ status = circ_init(ssock->pool->factory, &ssock->circ_buf_input, 512);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Initialize output circular buffer */
-+ status = circ_init(ssock->pool->factory, &ssock->circ_buf_output, 512);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Set the callback that allows GnuTLS to PUSH and PULL data
-+ * TO and FROM the transport layer */
-+ gnutls_transport_set_push_function(ssock->session, tls_data_push);
-+ gnutls_transport_set_pull_function(ssock->session, tls_data_pull);
-+
-+ /* Determine which cipher suite to support */
-+ status = tls_priorities_set(ssock);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Allocate credentials for handshaking and transmission */
-+ ret = gnutls_certificate_allocate_credentials(&ssock->xcred);
-+ if (ret < 0)
-+ goto out;
-+ gnutls_certificate_set_verify_function(ssock->xcred, tls_cert_verify_cb);
-+
-+ /* Load system trust file(s) */
-+ status = tls_trust_set(ssock);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Load user-provided CA, certificate and key if available */
-+ if (cert) {
-+ /* Load CA if one is specified. */
-+ if (cert->CA_file.slen) {
-+ ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ cert->CA_file.ptr,
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
-+ cert->CA_file.ptr,
-+ GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto out;
-+ }
-+ if (cert->CA_path.slen) {
-+ ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
-+ cert->CA_path.ptr,
-+ GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
-+ cert->CA_path.ptr,
-+ GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto out;
-+ }
-+
-+ /* Load certificate, key and pass if one is specified */
-+ if (cert->cert_file.slen && cert->privkey_file.slen) {
-+ const char *prikey_file = cert->privkey_file.ptr;
-+ const char *prikey_pass = cert->privkey_pass.slen
-+ ? cert->privkey_pass.ptr
-+ : NULL;
-+ ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
-+ cert->cert_file.ptr,
-+ prikey_file,
-+ GNUTLS_X509_FMT_PEM,
-+ prikey_pass,
-+ 0);
-+ if (ret != GNUTLS_E_SUCCESS)
-+ ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
-+ cert->cert_file.ptr,
-+ prikey_file,
-+ GNUTLS_X509_FMT_DER,
-+ prikey_pass,
-+ 0);
-+ if (ret < 0)
-+ goto out;
-+ }
-+ }
-+
-+ /* Require client certificate if asked */
-+ if (ssock->is_server && ssock->param.require_client_cert)
-+ gnutls_certificate_server_set_request(ssock->session,
-+ GNUTLS_CERT_REQUIRE);
-+
-+ /* Finally set credentials for this session */
-+ ret = gnutls_credentials_set(ssock->session,
-+ GNUTLS_CRD_CERTIFICATE, ssock->xcred);
-+ if (ret < 0)
-+ goto out;
-+
-+ ret = GNUTLS_E_SUCCESS;
-+out:
-+ return tls_status_from_err(ssock, ret);
-+}
-+
-+
-+/* Destroy GnuTLS credentials and session. */
-+static void tls_close(pj_ssl_sock_t *ssock)
-+{
-+ if (ssock->session) {
-+ gnutls_bye(ssock->session, GNUTLS_SHUT_RDWR);
-+ gnutls_deinit(ssock->session);
-+ ssock->session = NULL;
-+ }
-+
-+ if (ssock->xcred) {
-+ gnutls_certificate_free_credentials(ssock->xcred);
-+ ssock->xcred = NULL;
-+ }
-+
-+ /* Free GnuTLS library */
-+ if (ssock->tls_init_count) {
-+ ssock->tls_init_count--;
-+ tls_deinit();
-+ }
-+
-+ /* Destroy circular buffers */
-+ circ_deinit(&ssock->circ_buf_input);
-+ circ_deinit(&ssock->circ_buf_output);
-+}
-+
-+
-+/* Reset socket state. */
-+static void tls_sock_reset(pj_ssl_sock_t *ssock)
-+{
-+ ssock->connection_state = TLS_STATE_NULL;
-+
-+ tls_close(ssock);
-+
-+ if (ssock->asock) {
-+ pj_activesock_close(ssock->asock);
-+ ssock->asock = NULL;
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ }
-+ if (ssock->sock != PJ_INVALID_SOCKET) {
-+ pj_sock_close(ssock->sock);
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ }
-+
-+ ssock->last_err = tls_last_error = GNUTLS_E_SUCCESS;
-+}
-+
-+
-+/* Get Common Name field string from a general name string */
-+static void tls_cert_get_cn(const pj_str_t *gen_name, pj_str_t *cn)
-+{
-+ pj_str_t CN_sign = {"CN=", 3};
-+ char *p, *q;
-+
-+ pj_bzero(cn, sizeof(cn));
-+
-+ p = pj_strstr(gen_name, &CN_sign);
-+ if (!p)
-+ return;
-+
-+ p += 3; /* shift pointer to value part */
-+ pj_strset(cn, p, gen_name->slen - (p - gen_name->ptr));
-+ q = pj_strchr(cn, ',');
-+ if (q)
-+ cn->slen = q - p;
-+}
-+
-+
-+/* Get certificate info; in case the certificate info is already populated,
-+ * this function will check if the contents need updating by inspecting the
-+ * issuer and the serial number. */
-+static void tls_cert_get_info(pj_pool_t *pool, pj_ssl_cert_info *ci, gnutls_x509_crt_t cert)
-+{
-+ pj_bool_t update_needed;
-+ char buf[512] = { 0 };
-+ size_t bufsize = sizeof(buf);
-+ pj_uint8_t serial_no[64] = { 0 }; /* should be >= sizeof(ci->serial_no) */
-+ size_t serialsize = sizeof(serial_no);
-+ size_t len = sizeof(buf);
-+ int i, ret, seq = 0;
-+ pj_ssl_cert_name_type type;
-+
-+ pj_assert(pool && ci && cert);
-+
-+ /* Get issuer */
-+ gnutls_x509_crt_get_issuer_dn(cert, buf, &bufsize);
-+
-+ /* Get serial no */
-+ gnutls_x509_crt_get_serial(cert, serial_no, &serialsize);
-+
-+ /* Check if the contents need to be updated */
-+ update_needed = pj_strcmp2(&ci->issuer.info, buf) ||
-+ pj_memcmp(ci->serial_no, serial_no, serialsize);
-+ if (!update_needed)
-+ return;
-+
-+ /* Update cert info */
-+
-+ pj_bzero(ci, sizeof(pj_ssl_cert_info));
-+
-+ /* Version */
-+ ci->version = gnutls_x509_crt_get_version(cert);
-+
-+ /* Issuer */
-+ pj_strdup2(pool, &ci->issuer.info, buf);
-+ tls_cert_get_cn(&ci->issuer.info, &ci->issuer.cn);
-+
-+ /* Serial number */
-+ pj_memcpy(ci->serial_no, serial_no, sizeof(ci->serial_no));
-+
-+ /* Subject */
-+ bufsize = sizeof(buf);
-+ gnutls_x509_crt_get_dn(cert, buf, &bufsize);
-+ pj_strdup2(pool, &ci->subject.info, buf);
-+ tls_cert_get_cn(&ci->subject.info, &ci->subject.cn);
-+
-+ /* Validity */
-+ ci->validity.end.sec = gnutls_x509_crt_get_expiration_time(cert);
-+ ci->validity.start.sec = gnutls_x509_crt_get_activation_time(cert);
-+ ci->validity.gmt = 0;
-+
-+ /* Subject Alternative Name extension */
-+ if (ci->version >= 3) {
-+ char out[256] = { 0 };
-+ /* Get the number of all alternate names so that we can allocate
-+ * the correct number of bytes in subj_alt_name */
-+ while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len,
-+ NULL) != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
-+ seq++;
-+
-+ ci->subj_alt_name.entry = pj_pool_calloc(pool, seq,
-+ sizeof(*ci->subj_alt_name.entry));
-+ if (!ci->subj_alt_name.entry) {
-+ tls_last_error = GNUTLS_E_MEMORY_ERROR;
-+ return;
-+ }
-+
-+ /* Now populate the alternative names */
-+ for (i = 0; i < seq; i++) {
-+ len = sizeof(out) - 1;
-+ ret = gnutls_x509_crt_get_subject_alt_name(cert, i, out, &len, NULL);
-+ switch (ret) {
-+ case GNUTLS_SAN_IPADDRESS:
-+ type = PJ_SSL_CERT_NAME_IP;
-+ pj_inet_ntop2(len == sizeof(pj_in6_addr) ? pj_AF_INET6()
-+ : pj_AF_INET(),
-+ out, buf, sizeof(buf));
-+ break;
-+ case GNUTLS_SAN_URI:
-+ type = PJ_SSL_CERT_NAME_URI;
-+ break;
-+ case GNUTLS_SAN_RFC822NAME:
-+ type = PJ_SSL_CERT_NAME_RFC822;
-+ break;
-+ case GNUTLS_SAN_DNSNAME:
-+ type = PJ_SSL_CERT_NAME_DNS;
-+ break;
-+ default:
-+ type = PJ_SSL_CERT_NAME_UNKNOWN;
-+ break;
-+ }
-+
-+ if (len && type != PJ_SSL_CERT_NAME_UNKNOWN) {
-+ ci->subj_alt_name.entry[ci->subj_alt_name.cnt].type = type;
-+ pj_strdup2(pool,
-+ &ci->subj_alt_name.entry[ci->subj_alt_name.cnt].name,
-+ type == PJ_SSL_CERT_NAME_IP ? buf : out);
-+ ci->subj_alt_name.cnt++;
-+ }
-+ }
-+ /* TODO: if no DNS alt. names were found, we could check against
-+ * the commonName as per RFC3280. */
-+ }
-+}
-+
-+static void tls_cert_get_chain_raw(pj_pool_t *pool, pj_ssl_cert_info *ci, const gnutls_datum_t *certs, size_t certs_num)
-+{
-+ size_t i=0;
-+ ci->raw_chain.cert_raw = pj_pool_calloc(pool, certs_num, sizeof(*ci->raw_chain.cert_raw));
-+ ci->raw_chain.cnt = certs_num;
-+ for (i=0; i < certs_num; ++i) {
-+ const pj_str_t crt_raw = {(const char*)certs[i].data, (pj_ssize_t)certs[i].size};
-+ pj_strdup(pool, ci->raw_chain.cert_raw+i, &crt_raw);
-+ }
-+}
-+
-+/* Update local & remote certificates info. This function should be
-+ * called after handshake or renegotiation successfully completed. */
-+static void tls_cert_update(pj_ssl_sock_t *ssock)
-+{
-+ gnutls_x509_crt_t cert = NULL;
-+ const gnutls_datum_t *us;
-+ const gnutls_datum_t *certs;
-+ unsigned int certslen = 0;
-+ int ret = GNUTLS_CERT_INVALID;
-+
-+ pj_assert(ssock->connection_state == TLS_STATE_ESTABLISHED);
-+
-+ /* Get active local certificate */
-+ us = gnutls_certificate_get_ours(ssock->session);
-+ if (!us)
-+ goto us_out;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto us_out;
-+ ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ goto us_out;
-+
-+ tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
-+ tls_cert_get_chain_raw(ssock->pool, &ssock->local_cert_info, us, 1);
-+
-+us_out:
-+ tls_last_error = ret;
-+ if (cert)
-+ gnutls_x509_crt_deinit(cert);
-+ else
-+ pj_bzero(&ssock->local_cert_info, sizeof(pj_ssl_cert_info));
-+
-+ cert = NULL;
-+
-+ /* Get active remote certificate */
-+ certs = gnutls_certificate_get_peers(ssock->session, &certslen);
-+ if (certs == NULL || certslen == 0)
-+ goto peer_out;
-+
-+ ret = gnutls_x509_crt_init(&cert);
-+ if (ret < 0)
-+ goto peer_out;
-+
-+ ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_PEM);
-+ if (ret < 0)
-+ ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
-+ if (ret < 0)
-+ goto peer_out;
-+
-+ tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
-+ tls_cert_get_chain_raw(ssock->pool, &ssock->remote_cert_info, certs, certslen);
-+
-+peer_out:
-+ tls_last_error = ret;
-+ if (cert)
-+ gnutls_x509_crt_deinit(cert);
-+ else
-+ pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
-+}
-+
-+
-+/* When handshake completed:
-+ * - notify application
-+ * - if handshake failed, reset SSL state
-+ * - return PJ_FALSE when SSL socket instance is destroyed by application. */
-+static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
-+ pj_status_t status)
-+{
-+ pj_bool_t ret = PJ_TRUE;
-+
-+ /* Cancel handshake timer */
-+ if (ssock->timer.id == TIMER_HANDSHAKE_TIMEOUT) {
-+ pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ /* Update certificates info on successful handshake */
-+ if (status == PJ_SUCCESS)
-+ tls_cert_update(ssock);
-+
-+ /* Accepting */
-+ if (ssock->is_server) {
-+ if (status != PJ_SUCCESS) {
-+ /* Handshake failed in accepting, destroy our self silently. */
-+
-+ char errmsg[PJ_ERR_MSG_SIZE];
-+ char buf[PJ_INET6_ADDRSTRLEN + 10];
-+
-+ pj_strerror(status, errmsg, sizeof(errmsg));
-+ PJ_LOG(3, (ssock->pool->obj_name,
-+ "Handshake failed in accepting %s: %s",
-+ pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
-+ errmsg));
-+
-+ /* Workaround for ticket #985 */
-+#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
-+ if (ssock->param.timer_heap) {
-+ pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
-+
-+ tls_sock_reset(ssock);
-+
-+ ssock->timer.id = TIMER_CLOSE;
-+ pj_time_val_normalize(&interval);
-+ if (pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer, &interval) != 0)
-+ {
-+ ssock->timer.id = TIMER_NONE;
-+ pj_ssl_sock_close(ssock);
-+ }
-+ } else
-+#endif /* PJ_WIN32 */
-+ {
-+ pj_ssl_sock_close(ssock);
-+ }
-+
-+ return PJ_FALSE;
-+ }
-+ /* Notify application the newly accepted SSL socket */
-+ if (ssock->param.cb.on_accept_complete)
-+ ret = (*ssock->param.cb.on_accept_complete)
-+ (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr,
-+ pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr));
-+
-+ } else { /* Connecting */
-+ /* On failure, reset SSL socket state first, as app may try to
-+ * reconnect in the callback. */
-+ if (status != PJ_SUCCESS) {
-+ /* Server disconnected us, possibly due to negotiation failure */
-+ tls_sock_reset(ssock);
-+ }
-+ if (ssock->param.cb.on_connect_complete) {
-+
-+ ret = (*ssock->param.cb.on_connect_complete)(ssock, status);
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static write_data_t *alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len)
-+{
-+ send_buf_t *send_buf = &ssock->send_buf;
-+ pj_size_t avail_len, skipped_len = 0;
-+ char *reg1, *reg2;
-+ pj_size_t reg1_len, reg2_len;
-+ write_data_t *p;
-+
-+ /* Check buffer availability */
-+ avail_len = send_buf->max_len - send_buf->len;
-+ if (avail_len < len)
-+ return NULL;
-+
-+ /* If buffer empty, reset start pointer and return it */
-+ if (send_buf->len == 0) {
-+ send_buf->start = send_buf->buf;
-+ send_buf->len = len;
-+ p = (write_data_t*)send_buf->start;
-+ goto init_send_data;
-+ }
-+
-+ /* Free space may be wrapped/splitted into two regions, so let's
-+ * analyze them if any region can hold the write data. */
-+ reg1 = send_buf->start + send_buf->len;
-+ if (reg1 >= send_buf->buf + send_buf->max_len)
-+ reg1 -= send_buf->max_len;
-+ reg1_len = send_buf->max_len - send_buf->len;
-+ if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) {
-+ reg1_len = send_buf->buf + send_buf->max_len - reg1;
-+ reg2 = send_buf->buf;
-+ reg2_len = send_buf->start - send_buf->buf;
-+ } else {
-+ reg2 = NULL;
-+ reg2_len = 0;
-+ }
-+
-+ /* More buffer availability check, note that the write data must be in
-+ * a contigue buffer. */
-+ avail_len = PJ_MAX(reg1_len, reg2_len);
-+ if (avail_len < len)
-+ return NULL;
-+
-+ /* Get the data slot */
-+ if (reg1_len >= len) {
-+ p = (write_data_t*)reg1;
-+ } else {
-+ p = (write_data_t*)reg2;
-+ skipped_len = reg1_len;
-+ }
-+
-+ /* Update buffer length */
-+ send_buf->len += len + skipped_len;
-+
-+init_send_data:
-+ /* Init the new send data */
-+ pj_bzero(p, sizeof(*p));
-+ pj_list_init(p);
-+ pj_list_push_back(&ssock->send_pending, p);
-+
-+ return p;
-+}
-+
-+static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata)
-+{
-+ send_buf_t *buf = &ssock->send_buf;
-+ write_data_t *spl = &ssock->send_pending;
-+
-+ pj_assert(!pj_list_empty(&ssock->send_pending));
-+
-+ /* Free slot from the buffer */
-+ if (spl->next == wdata && spl->prev == wdata) {
-+ /* This is the only data, reset the buffer */
-+ buf->start = buf->buf;
-+ buf->len = 0;
-+ } else if (spl->next == wdata) {
-+ /* This is the first data, shift start pointer of the buffer and
-+ * adjust the buffer length.
-+ */
-+ buf->start = (char*)wdata->next;
-+ if (wdata->next > wdata) {
-+ buf->len -= ((char*)wdata->next - buf->start);
-+ } else {
-+ /* Overlapped */
-+ pj_size_t right_len, left_len;
-+ right_len = buf->buf + buf->max_len - (char*)wdata;
-+ left_len = (char*)wdata->next - buf->buf;
-+ buf->len -= (right_len + left_len);
-+ }
-+ } else if (spl->prev == wdata) {
-+ /* This is the last data, just adjust the buffer length */
-+ if (wdata->prev < wdata) {
-+ pj_size_t jump_len;
-+ jump_len = (char*)wdata -
-+ ((char*)wdata->prev + wdata->prev->record_len);
-+ buf->len -= (wdata->record_len + jump_len);
-+ } else {
-+ /* Overlapped */
-+ pj_size_t right_len, left_len;
-+ right_len = buf->buf + buf->max_len -
-+ ((char*)wdata->prev + wdata->prev->record_len);
-+ left_len = (char*)wdata + wdata->record_len - buf->buf;
-+ buf->len -= (right_len + left_len);
-+ }
-+ }
-+ /* For data in the middle buffer, just do nothing on the buffer. The slot
-+ * will be freed later when freeing the first/last data. */
-+
-+ /* Remove the data from send pending list */
-+ pj_list_erase(wdata);
-+}
-+
-+#if 0
-+/* Just for testing send buffer alloc/free */
-+#include <pj/rand.h>
-+pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool)
-+{
-+ enum { MAX_CHUNK_NUM = 20 };
-+ unsigned chunk_size, chunk_cnt, i;
-+ write_data_t *wdata[MAX_CHUNK_NUM] = {0};
-+ pj_time_val now;
-+ pj_ssl_sock_t *ssock = NULL;
-+ pj_ssl_sock_param param;
-+ pj_status_t status;
-+
-+ pj_gettimeofday(&now);
-+ pj_srand((unsigned)now.sec);
-+
-+ pj_ssl_sock_param_default(&param);
-+ status = pj_ssl_sock_create(pool, &param, &ssock);
-+ if (status != PJ_SUCCESS) {
-+ return status;
-+ }
-+
-+ if (ssock->send_buf.max_len == 0) {
-+ ssock->send_buf.buf = (char *)
-+ pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+ }
-+
-+ chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2;
-+ chunk_cnt = 0;
-+ for (i = 0; i < MAX_CHUNK_NUM; i++) {
-+ wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321);
-+ if (wdata[i])
-+ chunk_cnt++;
-+ else
-+ break;
-+ }
-+
-+ while (chunk_cnt) {
-+ i = pj_rand() % MAX_CHUNK_NUM;
-+ if (wdata[i]) {
-+ free_send_data(ssock, wdata[i]);
-+ wdata[i] = NULL;
-+ chunk_cnt--;
-+ }
-+ }
-+
-+ if (ssock->send_buf.len != 0)
-+ status = PJ_EBUG;
-+
-+ pj_ssl_sock_close(ssock);
-+ return status;
-+}
-+#endif
-+
-+/* Flush write circular buffer to network socket. */
-+static pj_status_t flush_circ_buf_output(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ pj_size_t orig_len, unsigned flags)
-+{
-+ pj_ssize_t len;
-+ write_data_t *wdata;
-+ pj_size_t needed_len;
-+ pj_status_t status;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Check if there is data in the circular buffer, flush it if any */
-+ if (circ_empty(&ssock->circ_buf_output)) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return PJ_SUCCESS;
-+ }
-+
-+ len = circ_size(&ssock->circ_buf_output);
-+
-+ /* Calculate buffer size needed, and align it to 8 */
-+ needed_len = len + sizeof(write_data_t);
-+ needed_len = ((needed_len + 7) >> 3) << 3;
-+
-+ /* Allocate buffer for send data */
-+ wdata = alloc_send_data(ssock, needed_len);
-+ if (wdata == NULL) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Copy the data and set its properties into the send data */
-+ pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t));
-+ wdata->key.user_data = wdata;
-+ wdata->app_key = send_key;
-+ wdata->record_len = needed_len;
-+ wdata->data_len = len;
-+ wdata->plain_data_len = orig_len;
-+ wdata->flags = flags;
-+ circ_read(&ssock->circ_buf_output, (pj_uint8_t *)&wdata->data, len);
-+
-+ /* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ /* Send it */
-+ if (ssock->param.sock_type == pj_SOCK_STREAM()) {
-+ status = pj_activesock_send(ssock->asock, &wdata->key,
-+ wdata->data.content, &len,
-+ flags);
-+ } else {
-+ status = pj_activesock_sendto(ssock->asock, &wdata->key,
-+ wdata->data.content, &len,
-+ flags,
-+ (pj_sockaddr_t*)&ssock->rem_addr,
-+ ssock->addr_len);
-+ }
-+
-+ if (status != PJ_EPENDING) {
-+ /* When the sending is not pending, remove the wdata from send
-+ * pending list. */
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ free_send_data(ssock, wdata);
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ }
-+
-+ return status;
-+}
-+
-+static void on_timer(pj_timer_heap_t *th, struct pj_timer_entry *te)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)te->user_data;
-+ int timer_id = te->id;
-+
-+ te->id = TIMER_NONE;
-+
-+ PJ_UNUSED_ARG(th);
-+
-+ switch (timer_id) {
-+ case TIMER_HANDSHAKE_TIMEOUT:
-+ PJ_LOG(1, (ssock->pool->obj_name, "TLS timeout after %d.%ds",
-+ ssock->param.timeout.sec, ssock->param.timeout.msec));
-+
-+ on_handshake_complete(ssock, PJ_ETIMEDOUT);
-+ break;
-+ case TIMER_CLOSE:
-+ pj_ssl_sock_close(ssock);
-+ break;
-+ default:
-+ pj_assert(!"Unknown timer");
-+ break;
-+ }
-+}
-+
-+
-+/* Try to perform an asynchronous handshake */
-+static pj_status_t tls_try_handshake(pj_ssl_sock_t *ssock)
-+{
-+ int ret;
-+ pj_status_t status;
-+
-+ /* Perform SSL handshake */
-+ ret = gnutls_handshake(ssock->session);
-+
-+ status = flush_circ_buf_output(ssock, &ssock->handshake_op_key, 0, 0);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ if (ret == GNUTLS_E_SUCCESS) {
-+ /* System are GO */
-+ ssock->connection_state = TLS_STATE_ESTABLISHED;
-+ status = PJ_SUCCESS;
-+ } else if (!gnutls_error_is_fatal(ret)) {
-+ /* Non fatal error, retry later (busy or again) */
-+ status = PJ_EPENDING;
-+ } else {
-+ /* Fatal error invalidates session, no fallback */
-+ status = PJ_EINVAL;
-+ }
-+
-+ tls_last_error = ret;
-+
-+ return status;
-+}
-+
-+
-+/*
-+ *******************************************************************
-+ * Active socket callbacks.
-+ *******************************************************************
-+ */
-+
-+/* PJ_TRUE asks the socket to read more data, PJ_FALSE takes it off the queue */
-+static pj_bool_t asock_on_data_read(pj_activesock_t *asock, void *data,
-+ pj_size_t size, pj_status_t status,
-+ pj_size_t *remainder)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)
-+ pj_activesock_get_user_data(asock);
-+
-+ pj_size_t app_remainder = 0;
-+
-+ if (data && size > 0) {
-+ /* Push data into input circular buffer (for GnuTLS) */
-+ pj_lock_acquire(ssock->circ_buf_input_mutex);
-+ circ_write(&ssock->circ_buf_input, data, size);
-+ pj_lock_release(ssock->circ_buf_input_mutex);
-+ }
-+
-+ /* Check if SSL handshake hasn't finished yet */
-+ if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
-+ pj_bool_t ret = PJ_TRUE;
-+
-+ if (status == PJ_SUCCESS)
-+ status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (status != PJ_EPENDING)
-+ ret = on_handshake_complete(ssock, status);
-+
-+ return ret;
-+ }
-+
-+ /* See if there is any decrypted data for the application */
-+ if (ssock->read_started) {
-+ do {
-+ /* Get read data structure at the end of the data */
-+ read_data_t *app_read_data = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
-+ int app_data_size = (int)(ssock->read_size - app_read_data->len);
-+
-+ /* Decrypt received data using GnuTLS (will read our input
-+ * circular buffer) */
-+ int decrypted_size = gnutls_record_recv(ssock->session,
-+ ((read_data_t *)app_read_data->data) +
-+ app_read_data->len,
-+ app_data_size);
-+
-+ if (decrypted_size > 0 || status != PJ_SUCCESS) {
-+ if (ssock->param.cb.on_data_read) {
-+ pj_bool_t ret;
-+ app_remainder = 0;
-+
-+ if (decrypted_size > 0)
-+ app_read_data->len += decrypted_size;
-+
-+ ret = (*ssock->param.cb.on_data_read)(ssock,
-+ app_read_data->data,
-+ app_read_data->len,
-+ status,
-+ &app_remainder);
-+
-+ if (!ret) {
-+ /* We've been destroyed */
-+ return PJ_FALSE;
-+ }
-+
-+ /* Application may have left some data to be consumed
-+ * later as remainder */
-+ app_read_data->len = app_remainder;
-+ }
-+
-+ /* Active socket signalled connection closed/error, this has
-+ * been signalled to the application along with any remaining
-+ * buffer. So, let's just reset SSL socket now. */
-+ if (status != PJ_SUCCESS) {
-+ tls_sock_reset(ssock);
-+ return PJ_FALSE;
-+ }
-+ } else if (decrypted_size == 0) {
-+ /* Nothing more to read */
-+
-+ return PJ_TRUE;
-+ } else if (decrypted_size == GNUTLS_E_AGAIN ||
-+ decrypted_size == GNUTLS_E_INTERRUPTED) {
-+ return PJ_TRUE;
-+ } else if (decrypted_size == GNUTLS_E_REHANDSHAKE) {
-+ /* Seems like we are renegotiating */
-+ pj_status_t try_handshake_status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (try_handshake_status != PJ_EPENDING) {
-+ if (!on_handshake_complete(ssock, try_handshake_status)) {
-+ return PJ_FALSE;
-+ }
-+ }
-+
-+ if (try_handshake_status != PJ_SUCCESS &&
-+ try_handshake_status != PJ_EPENDING) {
-+ return PJ_FALSE;
-+ }
-+ } else if (!gnutls_error_is_fatal(decrypted_size)) {
-+ /* non-fatal error, let's just continue */
-+ } else {
-+ return PJ_FALSE;
-+ }
-+ } while (PJ_TRUE);
-+ }
-+
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time new data is available from the active socket */
-+static pj_bool_t asock_on_data_sent(pj_activesock_t *asock,
-+ pj_ioqueue_op_key_t *send_key,
-+ pj_ssize_t sent)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)pj_activesock_get_user_data(asock);
-+
-+ PJ_UNUSED_ARG(send_key);
-+ PJ_UNUSED_ARG(sent);
-+
-+ if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
-+ /* Initial handshaking */
-+ pj_status_t status = tls_try_handshake(ssock);
-+
-+ /* Not pending is either success or failed */
-+ if (status != PJ_EPENDING)
-+ return on_handshake_complete(ssock, status);
-+
-+ } else if (send_key != &ssock->handshake_op_key) {
-+ /* Some data has been sent, notify application */
-+ write_data_t *wdata = (write_data_t*)send_key->user_data;
-+ if (ssock->param.cb.on_data_sent) {
-+ pj_bool_t ret;
-+ pj_ssize_t sent_len;
-+
-+ sent_len = sent > 0 ? wdata->plain_data_len : sent;
-+
-+ ret = (*ssock->param.cb.on_data_sent)(ssock, wdata->app_key,
-+ sent_len);
-+ if (!ret) {
-+ /* We've been destroyed */
-+ return PJ_FALSE;
-+ }
-+ }
-+
-+ /* Update write buffer state */
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ free_send_data(ssock, wdata);
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ } else {
-+ /* SSL re-negotiation is on-progress, just do nothing */
-+ /* FIXME: check if this is valid for GnuTLS too */
-+ }
-+
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time a new connection has been accepted (server) */
-+static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
-+ pj_sock_t newsock,
-+ const pj_sockaddr_t *src_addr,
-+ int src_addr_len)
-+{
-+ pj_ssl_sock_t *ssock_parent = (pj_ssl_sock_t *)
-+ pj_activesock_get_user_data(asock);
-+
-+ pj_ssl_sock_t *ssock;
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ unsigned int i;
-+ pj_status_t status;
-+
-+ PJ_UNUSED_ARG(src_addr_len);
-+
-+ /* Create new SSL socket instance */
-+ status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->newsock_param,
-+ &ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Update new SSL socket attributes */
-+ ssock->sock = newsock;
-+ ssock->parent = ssock_parent;
-+ ssock->is_server = PJ_TRUE;
-+ if (ssock_parent->cert) {
-+ status = pj_ssl_sock_set_certificate(ssock, ssock->pool,
-+ ssock_parent->cert);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+ }
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 1,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_return;
-+
-+ /* Update local address */
-+ ssock->addr_len = src_addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS) {
-+ /* This fails on few envs, e.g: win IOCP, just tolerate this and
-+ * use parent local address instead.
-+ */
-+ pj_sockaddr_cp(&ssock->local_addr, &ssock_parent->local_addr);
-+ }
-+
-+ /* Set remote address */
-+ pj_sockaddr_cp(&ssock->rem_addr, src_addr);
-+
-+ /* Create SSL context */
-+ status = tls_open(ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare read buffer */
-+ ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
-+ ssock->param.async_cnt,
-+ sizeof(void*));
-+ if (!ssock->asock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
-+ ssock->pool,
-+ ssock->param.read_buffer_size +
-+ sizeof(read_data_t*));
-+ if (!ssock->asock_rbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_data_read = asock_on_data_read;
-+ asock_cb.on_data_sent = asock_on_data_sent;
-+
-+ status = pj_activesock_create(ssock->pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Start reading */
-+ status = pj_activesock_start_read2(ssock->asock, ssock->pool,
-+ (unsigned)ssock->param.read_buffer_size,
-+ ssock->asock_rbuf,
-+ PJ_IOQUEUE_ALWAYS_ASYNC);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare write/send state */
-+ pj_assert(ssock->send_buf.max_len == 0);
-+ ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ if (!ssock->send_buf.buf)
-+ return PJ_ENOMEM;
-+
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+
-+ /* Start handshake timer */
-+ if (ssock->param.timer_heap &&
-+ (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0)) {
-+ pj_assert(ssock->timer.id == TIMER_NONE);
-+ ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
-+ status = pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer,
-+ &ssock->param.timeout);
-+ if (status != PJ_SUCCESS)
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ /* Start SSL handshake */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+
-+ status = tls_try_handshake(ssock);
-+
-+on_return:
-+ if (ssock && status != PJ_EPENDING)
-+ on_handshake_complete(ssock, status);
-+
-+ /* Must return PJ_TRUE whatever happened, as active socket must
-+ * continue listening.
-+ */
-+ return PJ_TRUE;
-+}
-+
-+
-+/* Callback every time a new connection has been completed (client) */
-+static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
-+ pj_status_t status)
-+{
-+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)
-+ pj_activesock_get_user_data(asock);
-+
-+ unsigned int i;
-+ int ret;
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Update local address */
-+ ssock->addr_len = sizeof(pj_sockaddr);
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Create SSL context */
-+ status = tls_open(ssock);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare read buffer */
-+ ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
-+ ssock->param.async_cnt,
-+ sizeof(void *));
-+ if (!ssock->asock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
-+ ssock->pool,
-+ ssock->param.read_buffer_size +
-+ sizeof(read_data_t *));
-+ if (!ssock->asock_rbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ /* Start read */
-+ status = pj_activesock_start_read2(ssock->asock, ssock->pool,
-+ (unsigned) ssock->param.read_buffer_size,
-+ ssock->asock_rbuf,
-+ PJ_IOQUEUE_ALWAYS_ASYNC);
-+ if (status != PJ_SUCCESS)
-+ goto on_return;
-+
-+ /* Prepare write/send state */
-+ pj_assert(ssock->send_buf.max_len == 0);
-+ ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
-+ ssock->param.send_buffer_size);
-+ if (!ssock->send_buf.buf)
-+ return PJ_ENOMEM;
-+
-+ ssock->send_buf.max_len = ssock->param.send_buffer_size;
-+ ssock->send_buf.start = ssock->send_buf.buf;
-+ ssock->send_buf.len = 0;
-+
-+ /* Set server name to connect */
-+ if (ssock->param.server_name.slen) {
-+ /* Server name is null terminated already */
-+ ret = gnutls_server_name_set(ssock->session, GNUTLS_NAME_DNS,
-+ ssock->param.server_name.ptr,
-+ ssock->param.server_name.slen);
-+ if (ret < 0) {
-+ PJ_LOG(3, (ssock->pool->obj_name,
-+ "gnutls_server_name_set() failed: %s",
-+ gnutls_strerror(ret)));
-+ }
-+ }
-+
-+ /* Start handshake */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+
-+ status = tls_try_handshake(ssock);
-+ if (status != PJ_EPENDING)
-+ goto on_return;
-+
-+ return PJ_TRUE;
-+
-+on_return:
-+ return on_handshake_complete(ssock, status);
-+}
-+
-+static void tls_ciphers_fill(void)
-+{
-+ if (!tls_available_ciphers) {
-+ tls_init();
-+ tls_deinit();
-+ }
-+}
-+
-+/*
-+ *******************************************************************
-+ * API
-+ *******************************************************************
-+ */
-+
-+/* Load credentials from files. */
-+PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
-+ const pj_str_t *CA_file,
-+ const pj_str_t *cert_file,
-+ const pj_str_t *privkey_file,
-+ const pj_str_t *privkey_pass,
-+ pj_ssl_cert_t **p_cert)
-+{
-+ return pj_ssl_cert_load_from_files2(pool, CA_file, NULL, cert_file,
-+ privkey_file, privkey_pass, p_cert);
-+}
-+
-+/* Load credentials from files. */
-+PJ_DECL(pj_status_t) pj_ssl_cert_load_from_files2(
-+ pj_pool_t *pool,
-+ const pj_str_t *CA_file,
-+ const pj_str_t *CA_path,
-+ const pj_str_t *cert_file,
-+ const pj_str_t *privkey_file,
-+ const pj_str_t *privkey_pass,
-+ pj_ssl_cert_t **p_cert)
-+{
-+ pj_ssl_cert_t *cert;
-+
-+ PJ_ASSERT_RETURN(pool && (CA_file || CA_path) && cert_file &&
-+ privkey_file,
-+ PJ_EINVAL);
-+
-+ cert = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
-+ if (CA_file) {
-+ pj_strdup_with_null(pool, &cert->CA_file, CA_file);
-+ }
-+ if (CA_path) {
-+ pj_strdup_with_null(pool, &cert->CA_path, CA_path);
-+ }
-+ pj_strdup_with_null(pool, &cert->cert_file, cert_file);
-+ pj_strdup_with_null(pool, &cert->privkey_file, privkey_file);
-+ pj_strdup_with_null(pool, &cert->privkey_pass, privkey_pass);
-+
-+ *p_cert = cert;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+/* Store credentials. */
-+PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_ssl_cert_t *cert)
-+{
-+ pj_ssl_cert_t *cert_;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && cert, PJ_EINVAL);
-+
-+ cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
-+ pj_memcpy(cert_, cert, sizeof(cert));
-+ pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
-+ pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
-+ pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
-+ pj_strdup_with_null(pool, &cert_->privkey_file, &cert->privkey_file);
-+ pj_strdup_with_null(pool, &cert_->privkey_pass, &cert->privkey_pass);
-+
-+ ssock->cert = cert_;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Get available ciphers. */
-+PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
-+ unsigned *cipher_num)
-+{
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
-+
-+ tls_ciphers_fill();
-+
-+ if (!tls_available_ciphers) {
-+ *cipher_num = 0;
-+ return PJ_ENOTFOUND;
-+ }
-+
-+ *cipher_num = PJ_MIN(*cipher_num, tls_available_ciphers);
-+
-+ for (i = 0; i < *cipher_num; ++i)
-+ ciphers[i] = tls_ciphers[i].id;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Get cipher name string. */
-+PJ_DEF(const char *)pj_ssl_cipher_name(pj_ssl_cipher cipher)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (cipher == tls_ciphers[i].id)
-+ return tls_ciphers[i].name;
-+ }
-+
-+ return NULL;
-+}
-+
-+
-+/* Get cipher identifier. */
-+PJ_DEF(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (!pj_ansi_stricmp(tls_ciphers[i].name, cipher_name))
-+ return tls_ciphers[i].id;
-+ }
-+
-+ return PJ_TLS_UNKNOWN_CIPHER;
-+}
-+
-+
-+/* Check if the specified cipher is supported by the TLS backend. */
-+PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
-+{
-+ unsigned int i;
-+
-+ tls_ciphers_fill();
-+
-+ for (i = 0; i < tls_available_ciphers; ++i) {
-+ if (cipher == tls_ciphers[i].id)
-+ return PJ_TRUE;
-+ }
-+
-+ return PJ_FALSE;
-+}
-+
-+/* Create SSL socket instance. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_create(pj_pool_t *pool,
-+ const pj_ssl_sock_param *param,
-+ pj_ssl_sock_t **p_ssock)
-+{
-+ pj_ssl_sock_t *ssock;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(param->sock_type == pj_SOCK_STREAM(), PJ_ENOTSUP);
-+
-+ pool = pj_pool_create(pool->factory, "tls%p", 512, 512, NULL);
-+
-+ /* Create secure socket */
-+ ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
-+ ssock->pool = pool;
-+ ssock->sock = PJ_INVALID_SOCKET;
-+ ssock->connection_state = TLS_STATE_NULL;
-+ pj_list_init(&ssock->write_pending);
-+ pj_list_init(&ssock->write_pending_empty);
-+ pj_list_init(&ssock->send_pending);
-+ pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer);
-+ pj_ioqueue_op_key_init(&ssock->handshake_op_key,
-+ sizeof(pj_ioqueue_op_key_t));
-+
-+ /* Create secure socket mutex */
-+ status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_output_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Create input circular buffer mutex */
-+ status = pj_lock_create_simple_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_input_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Create output circular buffer mutex */
-+ status = pj_lock_create_simple_mutex(pool, pool->obj_name,
-+ &ssock->circ_buf_output_mutex);
-+ if (status != PJ_SUCCESS)
-+ return status;
-+
-+ /* Init secure socket param */
-+ ssock->param = *param;
-+ ssock->param.read_buffer_size = ((ssock->param.read_buffer_size + 7) >> 3) << 3;
-+
-+ if (param->ciphers_num > 0) {
-+ unsigned int i;
-+ ssock->param.ciphers = (pj_ssl_cipher *)
-+ pj_pool_calloc(pool, param->ciphers_num,
-+ sizeof(pj_ssl_cipher));
-+ if (!ssock->param.ciphers)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < param->ciphers_num; ++i)
-+ ssock->param.ciphers[i] = param->ciphers[i];
-+ }
-+
-+ /* Server name must be null-terminated */
-+ pj_strdup_with_null(pool, &ssock->param.server_name, &param->server_name);
-+
-+ /* Finally */
-+ *p_ssock = ssock;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ * Close the secure socket. This will unregister the socket from the
-+ * ioqueue and ultimately close the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
-+{
-+ pj_pool_t *pool;
-+
-+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
-+
-+ if (!ssock->pool)
-+ return PJ_SUCCESS;
-+
-+ if (ssock->timer.id != TIMER_NONE) {
-+ pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ tls_sock_reset(ssock);
-+
-+ pj_lock_destroy(ssock->circ_buf_output_mutex);
-+ pj_lock_destroy(ssock->circ_buf_input_mutex);
-+
-+ pool = ssock->pool;
-+ ssock->pool = NULL;
-+ if (pool)
-+ pj_pool_release(pool);
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Associate arbitrary data with the secure socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data(pj_ssl_sock_t *ssock,
-+ void *user_data)
-+{
-+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
-+
-+ ssock->param.user_data = user_data;
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Retrieve the user data previously associated with this secure socket. */
-+PJ_DEF(void *)pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
-+{
-+ PJ_ASSERT_RETURN(ssock, NULL);
-+
-+ return ssock->param.user_data;
-+}
-+
-+
-+/* Retrieve the local address and port used by specified SSL socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
-+ pj_ssl_sock_info *info)
-+{
-+ pj_bzero(info, sizeof(*info));
-+
-+ /* Established flag */
-+ info->established = (ssock->connection_state == TLS_STATE_ESTABLISHED);
-+
-+ /* Protocol */
-+ info->proto = ssock->param.proto;
-+
-+ /* Local address */
-+ pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
-+
-+ if (info->established) {
-+ int i;
-+ gnutls_cipher_algorithm_t lookup;
-+ gnutls_cipher_algorithm_t cipher;
-+
-+ /* Current cipher */
-+ cipher = gnutls_cipher_get(ssock->session);
-+ for (i = 0; ; i++) {
-+ unsigned char id[2];
-+ const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
-+ NULL, &lookup, NULL,
-+ NULL);
-+ if (suite) {
-+ if (lookup == cipher) {
-+ info->cipher = (pj_uint32_t) ((id[0] << 8) | id[1]);
-+ break;
-+ }
-+ } else
-+ break;
-+ }
-+
-+ /* Remote address */
-+ pj_sockaddr_cp(&info->remote_addr, &ssock->rem_addr);
-+
-+ /* Certificates info */
-+ info->local_cert_info = &ssock->local_cert_info;
-+ info->remote_cert_info = &ssock->remote_cert_info;
-+
-+ /* Verification status */
-+ info->verify_status = ssock->verify_status;
-+ }
-+
-+ /* Last known GnuTLS error code */
-+ info->last_native_err = ssock->last_err;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Starts read operation on this secure socket. */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_read(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ pj_uint32_t flags)
-+{
-+ void **readbuf;
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ readbuf = (void**) pj_pool_calloc(pool, ssock->param.async_cnt,
-+ sizeof(void *));
-+ if (!readbuf)
-+ return PJ_ENOMEM;
-+
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ readbuf[i] = pj_pool_alloc(pool, buff_size);
-+ if (!readbuf[i])
-+ return PJ_ENOMEM;
-+ }
-+
-+ return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
-+}
-+
-+
-+/*
-+ * Same as #pj_ssl_sock_start_read(), except that the application
-+ * supplies the buffers for the read operation so that the acive socket
-+ * does not have to allocate the buffers.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ void *readbuf[],
-+ pj_uint32_t flags)
-+{
-+ unsigned int i;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && buff_size && readbuf, PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Create SSL socket read buffer */
-+ ssock->ssock_rbuf = (read_data_t*)pj_pool_calloc(pool,
-+ ssock->param.async_cnt,
-+ sizeof(read_data_t));
-+ if (!ssock->ssock_rbuf)
-+ return PJ_ENOMEM;
-+
-+ /* Store SSL socket read buffer pointer in the activesock read buffer */
-+ for (i = 0; i < ssock->param.async_cnt; ++i) {
-+ read_data_t **p_ssock_rbuf =
-+ OFFSET_OF_READ_DATA_PTR(ssock, ssock->asock_rbuf[i]);
-+
-+ ssock->ssock_rbuf[i].data = readbuf[i];
-+ ssock->ssock_rbuf[i].len = 0;
-+
-+ *p_ssock_rbuf = &ssock->ssock_rbuf[i];
-+ }
-+
-+ ssock->read_size = buff_size;
-+ ssock->read_started = PJ_TRUE;
-+ ssock->read_flags = flags;
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/*
-+ * Same as pj_ssl_sock_start_read(), except that this function is used
-+ * only for datagram sockets, and it will trigger \a on_data_recvfrom()
-+ * callback instead.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ pj_uint32_t flags)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(pool);
-+ PJ_UNUSED_ARG(buff_size);
-+ PJ_UNUSED_ARG(flags);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+
-+/*
-+ * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
-+ * operation takes the buffer from the argument rather than creating
-+ * new ones.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ unsigned buff_size,
-+ void *readbuf[],
-+ pj_uint32_t flags)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(pool);
-+ PJ_UNUSED_ARG(buff_size);
-+ PJ_UNUSED_ARG(readbuf);
-+ PJ_UNUSED_ARG(flags);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+
-+/*
-+ * Write the plain data to GnuTLS, it will be encrypted by gnutls_record_send()
-+ * and sent via tls_data_push. Note that re-negotitation may be on progress, so
-+ * sending data should be delayed until re-negotiation is completed.
-+ */
-+static pj_status_t tls_write(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t size, unsigned flags)
-+{
-+ pj_status_t status;
-+ int nwritten;
-+ pj_ssize_t total_written = 0;
-+
-+ /* Ask GnuTLS to encrypt our plaintext now. GnuTLS will use the push
-+ * callback to actually write the encrypted bytes into our output circular
-+ * buffer. GnuTLS may refuse to "send" everything at once, but since we are
-+ * not really sending now, we will just call it again now until it succeeds
-+ * (or fails in a fatal way). */
-+ while (total_written < size) {
-+ /* Try encrypting using GnuTLS */
-+ nwritten = gnutls_record_send(ssock->session, ((read_data_t *)data) + total_written,
-+ size);
-+
-+ if (nwritten > 0) {
-+ /* Good, some data was encrypted and written */
-+ total_written += nwritten;
-+ } else {
-+ /* Normally we would have to retry record_send but our internal
-+ * state has not changed, so we have to ask for more data first.
-+ * We will just try again later, although this should never happen.
-+ */
-+ return tls_status_from_err(ssock, nwritten);
-+ }
-+ }
-+
-+ /* All encrypted data is written to the output circular buffer;
-+ * now send it on the socket (or notify problem). */
-+ if (total_written == size)
-+ status = flush_circ_buf_output(ssock, send_key, size, flags);
-+ else
-+ status = PJ_ENOMEM;
-+
-+ return status;
-+}
-+
-+
-+/* Flush delayed data sending in the write pending list. */
-+static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock)
-+{
-+ /* Check for another ongoing flush */
-+ if (ssock->flushing_write_pend) {
-+ return PJ_EBUSY;
-+ }
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Again, check for another ongoing flush */
-+ if (ssock->flushing_write_pend) {
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+ return PJ_EBUSY;
-+ }
-+
-+ /* Set ongoing flush flag */
-+ ssock->flushing_write_pend = PJ_TRUE;
-+
-+ while (!pj_list_empty(&ssock->write_pending)) {
-+ write_data_t *wp;
-+ pj_status_t status;
-+
-+ wp = ssock->write_pending.next;
-+
-+ /* Ticket #1573: Don't hold mutex while calling socket send. */
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ status = tls_write(ssock, &wp->key, wp->data.ptr,
-+ wp->plain_data_len, wp->flags);
-+ if (status != PJ_SUCCESS) {
-+ /* Reset ongoing flush flag first. */
-+ ssock->flushing_write_pend = PJ_FALSE;
-+ return status;
-+ }
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+ pj_list_erase(wp);
-+ pj_list_push_back(&ssock->write_pending_empty, wp);
-+ }
-+
-+ /* Reset ongoing flush flag */
-+ ssock->flushing_write_pend = PJ_FALSE;
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ return PJ_SUCCESS;
-+}
-+
-+
-+/* Sending is delayed, push back the sending data into pending list. */
-+static pj_status_t delay_send(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t size,
-+ unsigned flags)
-+{
-+ write_data_t *wp;
-+
-+ pj_lock_acquire(ssock->circ_buf_output_mutex);
-+
-+ /* Init write pending instance */
-+ if (!pj_list_empty(&ssock->write_pending_empty)) {
-+ wp = ssock->write_pending_empty.next;
-+ pj_list_erase(wp);
-+ } else {
-+ wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t);
-+ }
-+
-+ wp->app_key = send_key;
-+ wp->plain_data_len = size;
-+ wp->data.ptr = data;
-+ wp->flags = flags;
-+
-+ pj_list_push_back(&ssock->write_pending, wp);
-+
-+ pj_lock_release(ssock->circ_buf_output_mutex);
-+
-+ /* Must return PJ_EPENDING */
-+ return PJ_EPENDING;
-+}
-+
-+
-+/**
-+ * Send data using the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_send(pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t *size,
-+ unsigned flags)
-+{
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && data && size && (*size > 0), PJ_EINVAL);
-+ PJ_ASSERT_RETURN(ssock->connection_state==TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Flush delayed send first. Sending data might be delayed when
-+ * re-negotiation is on-progress. */
-+ status = flush_delayed_send(ssock);
-+ if (status == PJ_EBUSY) {
-+ /* Re-negotiation or flushing is on progress, delay sending */
-+ status = delay_send(ssock, send_key, data, *size, flags);
-+ goto on_return;
-+ } else if (status != PJ_SUCCESS) {
-+ goto on_return;
-+ }
-+
-+ /* Write data to SSL */
-+ status = tls_write(ssock, send_key, data, *size, flags);
-+ if (status == PJ_EBUSY) {
-+ /* Re-negotiation is on progress, delay sending */
-+ status = delay_send(ssock, send_key, data, *size, flags);
-+ }
-+
-+on_return:
-+ return status;
-+}
-+
-+
-+/**
-+ * Send datagram using the socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
-+ pj_ioqueue_op_key_t *send_key,
-+ const void *data, pj_ssize_t *size,
-+ unsigned flags,
-+ const pj_sockaddr_t *addr, int addr_len)
-+{
-+ PJ_UNUSED_ARG(ssock);
-+ PJ_UNUSED_ARG(send_key);
-+ PJ_UNUSED_ARG(data);
-+ PJ_UNUSED_ARG(size);
-+ PJ_UNUSED_ARG(flags);
-+ PJ_UNUSED_ARG(addr);
-+ PJ_UNUSED_ARG(addr_len);
-+
-+ return PJ_ENOTSUP;
-+}
-+
-+/**
-+ * Starts asynchronous socket accept() operations on this secure socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ int addr_len)
-+{
-+ return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len,
-+ &ssock->param);
-+}
-+
-+/**
-+ * Starts asynchronous socket accept() operations on this secure socket.
-+ */
-+PJ_DEF(pj_status_t) pj_ssl_sock_start_accept2 (pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ int addr_len,
-+ const pj_ssl_sock_param *newsock_param)
-+{
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
-+
-+ /* Verify new socket parameters */
-+ if (newsock_param->grp_lock != ssock->param.grp_lock ||
-+ newsock_param->sock_af != ssock->param.sock_af ||
-+ newsock_param->sock_type != ssock->param.sock_type)
-+ {
-+ return PJ_EINVAL;
-+ }
-+
-+ /* Create socket */
-+ status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
-+ &ssock->sock);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Apply SO_REUSEADDR */
-+ if (ssock->param.reuse_addr) {
-+ int enabled = 1;
-+ status = pj_sock_setsockopt(ssock->sock, pj_SOL_SOCKET(),
-+ pj_SO_REUSEADDR(),
-+ &enabled, sizeof(enabled));
-+ if (status != PJ_SUCCESS) {
-+ PJ_PERROR(4,(ssock->pool->obj_name, status,
-+ "Warning: error applying SO_REUSEADDR"));
-+ }
-+ }
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 2,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_error;
-+
-+ /* Bind socket */
-+ status = pj_sock_bind(ssock->sock, localaddr, addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Start listening to the address */
-+ status = pj_sock_listen(ssock->sock, PJ_SOMAXCONN);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_accept_complete = asock_on_accept_complete;
-+
-+ status = pj_activesock_create(pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Start accepting */
-+ pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param);
-+ status = pj_activesock_start_accept(ssock->asock, pool);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Update local address */
-+ ssock->addr_len = addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ if (status != PJ_SUCCESS)
-+ pj_sockaddr_cp(&ssock->local_addr, localaddr);
-+
-+ ssock->is_server = PJ_TRUE;
-+
-+ return PJ_SUCCESS;
-+
-+on_error:
-+ tls_sock_reset(ssock);
-+ return status;
-+}
-+
-+
-+/**
-+ * Starts asynchronous socket connect() operation.
-+ */
-+PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
-+ pj_pool_t *pool,
-+ const pj_sockaddr_t *localaddr,
-+ const pj_sockaddr_t *remaddr,
-+ int addr_len)
-+{
-+ pj_activesock_cb asock_cb;
-+ pj_activesock_cfg asock_cfg;
-+ pj_status_t status;
-+
-+ PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
-+ PJ_EINVAL);
-+
-+ /* Create socket */
-+ status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
-+ &ssock->sock);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Apply QoS, if specified */
-+ status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
-+ &ssock->param.qos_params, 2,
-+ ssock->pool->obj_name, NULL);
-+ if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
-+ goto on_error;
-+
-+ /* Bind socket */
-+ status = pj_sock_bind(ssock->sock, localaddr, addr_len);
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Create active socket */
-+ pj_activesock_cfg_default(&asock_cfg);
-+ asock_cfg.async_cnt = ssock->param.async_cnt;
-+ asock_cfg.concurrency = ssock->param.concurrency;
-+ asock_cfg.whole_data = PJ_TRUE;
-+
-+ pj_bzero(&asock_cb, sizeof(asock_cb));
-+ asock_cb.on_connect_complete = asock_on_connect_complete;
-+ asock_cb.on_data_read = asock_on_data_read;
-+ asock_cb.on_data_sent = asock_on_data_sent;
-+
-+ status = pj_activesock_create(pool,
-+ ssock->sock,
-+ ssock->param.sock_type,
-+ &asock_cfg,
-+ ssock->param.ioqueue,
-+ &asock_cb,
-+ ssock,
-+ &ssock->asock);
-+
-+ if (status != PJ_SUCCESS)
-+ goto on_error;
-+
-+ /* Save remote address */
-+ pj_sockaddr_cp(&ssock->rem_addr, remaddr);
-+
-+ /* Start timer */
-+ if (ssock->param.timer_heap &&
-+ (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0))
-+ {
-+ pj_assert(ssock->timer.id == TIMER_NONE);
-+ ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
-+ status = pj_timer_heap_schedule(ssock->param.timer_heap,
-+ &ssock->timer,
-+ &ssock->param.timeout);
-+ if (status != PJ_SUCCESS)
-+ ssock->timer.id = TIMER_NONE;
-+ }
-+
-+ status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
-+ addr_len);
-+
-+ if (status == PJ_SUCCESS)
-+ asock_on_connect_complete(ssock->asock, PJ_SUCCESS);
-+ else if (status != PJ_EPENDING)
-+ goto on_error;
-+
-+ /* Update local address */
-+ ssock->addr_len = addr_len;
-+ status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
-+ &ssock->addr_len);
-+ /* Note that we may not get an IP address here. This can
-+ * happen for example on Windows, where getsockname()
-+ * would return 0.0.0.0 if socket has just started the
-+ * async connect. In this case, just leave the local
-+ * address with 0.0.0.0 for now; it will be updated
-+ * once the socket is established.
-+ */
-+
-+ /* Update socket state */
-+ ssock->is_server = PJ_FALSE;
-+
-+ return PJ_EPENDING;
-+
-+on_error:
-+ tls_sock_reset(ssock);
-+ return status;
-+}
-+
-+
-+PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
-+{
-+ int status;
-+
-+ /* Nothing established yet */
-+ PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
-+ PJ_EINVALIDOP);
-+
-+ /* Cannot renegotiate; we're a client */
-+ /* FIXME: in fact maybe that's not true */
-+ PJ_ASSERT_RETURN(!ssock->is_server, PJ_EINVALIDOP);
-+
-+ /* First call gnutls_rehandshake() to see if this is even possible */
-+ status = gnutls_rehandshake(ssock->session);
-+
-+ if (status == GNUTLS_E_SUCCESS) {
-+ /* Rehandshake is possible, so try a GnuTLS handshake now. The eventual
-+ * gnutls_record_recv() calls could return a few specific values during
-+ * this state:
-+ *
-+ * - GNUTLS_E_REHANDSHAKE: rehandshake message processing
-+ * - GNUTLS_E_WARNING_ALERT_RECEIVED: client does not wish to
-+ * renegotiate
-+ */
-+ ssock->connection_state = TLS_STATE_HANDSHAKING;
-+ status = tls_try_handshake(ssock);
-+
-+ return status;
-+ } else {
-+ return tls_status_from_err(ssock, status);
-+ }
-+}
-+
-+#endif /* PJ_HAS_SSL_SOCK */
---- a/pjlib/src/pj/ssl_sock_ossl.c
-+++ b/pjlib/src/pj/ssl_sock_ossl.c
-@@ -32,8 +32,10 @@
- #include <pj/timer.h>
-
-
--/* Only build when PJ_HAS_SSL_SOCK is enabled */
--#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK!=0
-+/* Only build when PJ_HAS_SSL_SOCK is enabled and when PJ_HAS_TLS_SOCK is
-+ * disabled (meaning GnuTLS is off) */
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
-
- #define THIS_FILE "ssl_sock_ossl.c"
-
---- a/pjmedia/src/pjmedia/transport_srtp.c
-+++ b/pjmedia/src/pjmedia/transport_srtp.c
-@@ -30,7 +30,8 @@
-
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
-
--#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
- # include <openssl/rand.h>
-
- /* Suppress compile warning of OpenSSL deprecation (OpenSSL is deprecated
-@@ -1113,7 +1114,8 @@ static pj_status_t generate_crypto_attr_value(pj_pool_t *pool,
- key_ok = PJ_TRUE;
-
-
--#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
-+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
-+ defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
-
- /* Include OpenSSL libraries for MSVC */
- # ifdef _MSC_VER
diff --git a/libraries/pjproject-ring/patches/pj_uwp_ice_sess.patch b/libraries/pjproject-ring/patches/pj_uwp_ice_sess.patch
deleted file mode 100644
index ce4e0b4898..0000000000
--- a/libraries/pjproject-ring/patches/pj_uwp_ice_sess.patch
+++ /dev/null
@@ -1,25 +0,0 @@
---- a/pjnath/include/pjnath/ice_strans.h
-+++ b/pjnath/include/pjnath/ice_strans.h
-@@ -930,6 +930,7 @@
- int dst_addr_len);
-
-
-+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess(pj_ice_strans *ice_st);
- /**
- * @}
- */
---- a/pjnath/src/pjnath/ice_strans.c
-+++ b/pjnath/src/pjnath/ice_strans.c
-@@ -1465,6 +1468,11 @@
- return PJ_EINVALIDOP;
- }
-
-+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess( pj_ice_strans *ice_st )
-+{
-+ return ice_st->ice;
-+}
-+
- /*
- * Callback called by ICE session when ICE processing is complete, either
- * successfully or with failure.
- \ No newline at end of file
diff --git a/libraries/pjproject-ring/patches/pj_uwp_multiple_listeners.patch b/libraries/pjproject-ring/patches/pj_uwp_multiple_listeners.patch
deleted file mode 100644
index 893bcfbdca..0000000000
--- a/libraries/pjproject-ring/patches/pj_uwp_multiple_listeners.patch
+++ /dev/null
@@ -1,64 +0,0 @@
---- a/pjsip/src/pjsip/sip_transport.c
-+++ b/pjsip/src/pjsip/sip_transport.c
-@@ -1248,22 +1248,22 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr,
-
- pj_lock_acquire(mgr->lock);
-
-- /* Check that no factory with the same type has been registered. */
-+ /* Check that no factory with the same type and bound address has been registered. */
- status = PJ_SUCCESS;
- for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
-- if (p->type == tpf->type) {
-- status = PJSIP_ETYPEEXISTS;
-- break;
-- }
-- if (p == tpf) {
-- status = PJ_EEXISTS;
-- break;
-- }
-+ if (p->type == tpf->type && !pj_sockaddr_cmp(&tpf->local_addr, &p->local_addr)) {
-+ status = PJSIP_ETYPEEXISTS;
-+ break;
-+ }
-+ if (p == tpf) {
-+ status = PJ_EEXISTS;
-+ break;
-+ }
- }
-
- if (status != PJ_SUCCESS) {
-- pj_lock_release(mgr->lock);
-- return status;
-+ pj_lock_release(mgr->lock);
-+ return status;
- }
-
- pj_list_insert_before(&mgr->factory_list, tpf);
-@@ -2047,13 +2047,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
- pj_memcpy(&key.rem_addr, remote, addr_len);
-
- transport = (pjsip_transport*)
-- pj_hash_get(mgr->table, &key, key_len, NULL);
--
-+ pj_hash_get(mgr->table, &key, key_len, NULL);
-+ unsigned flag = pjsip_transport_get_flag_from_type(type);
- if (transport == NULL) {
-- unsigned flag = pjsip_transport_get_flag_from_type(type);
- const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
-
--
- /* Ignore address for loop transports. */
- if (type == PJSIP_TRANSPORT_LOOP ||
- type == PJSIP_TRANSPORT_LOOP_DGRAM)
-@@ -2135,6 +2135,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
- }
-
- } else {
-+ /* Make sure we don't use another factory than the one given if secure flag is set */
-+ if (flag & PJSIP_TRANSPORT_SECURE) {
-+ TRACE_((THIS_FILE, "Can't create new TLS transport with no provided suitable TLS listener."));
-+ return PJSIP_ETPNOTSUITABLE;
-+ }
-
- /* Find factory with type matches the destination type */
- factory = mgr->factory_list.next;
diff --git a/libraries/pjproject-ring/patches/pj_win.patch b/libraries/pjproject-ring/patches/pj_win.patch
deleted file mode 100644
index c1c4c78f19..0000000000
--- a/libraries/pjproject-ring/patches/pj_win.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- pjproject/pjlib/include/pj/compat/string.h.orig 2014-09-08 16:17:36.471214560 -0400
-+++ pjproject/pjlib/include/pj/compat/string.h 2014-09-08 16:09:22.095207141 -0400
-@@ -43,7 +43,7 @@
- # include <stdlib.h>
- #endif
-
--#if defined(_MSC_VER)
-+#if defined(PJ_WIN32)
- # define strcasecmp _stricmp
- # define strncasecmp _strnicmp
- # define snprintf _snprintf
diff --git a/libraries/pjproject-ring/pjproject-ring.SlackBuild b/libraries/pjproject-ring/pjproject-ring.SlackBuild
deleted file mode 100644
index d8bf842e34..0000000000
--- a/libraries/pjproject-ring/pjproject-ring.SlackBuild
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/sh
-
-# Slackware build script for pjproject-ring
-
-# Copyright 2017 Mario Preksavec, Zagreb, Croatia
-# All rights reserved.
-#
-# Redistribution and use of this script, with or without modification, is
-# permitted provided that the following conditions are met:
-#
-# 1. Redistributions of this script must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
-# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-PRGNAM=pjproject-ring
-VERSION=${VERSION:-2.6}
-BUILD=${BUILD:-1}
-TAG=${TAG:-_SBo}
-
-SRCNAM=pjproject
-
-if [ -z "$ARCH" ]; then
- case "$( uname -m )" in
- i?86) ARCH=i586 ;;
- arm*) ARCH=arm ;;
- *) ARCH=$( uname -m ) ;;
- esac
-fi
-
-CWD=$(pwd)
-TMP=${TMP:-/tmp/SBo}
-PKG=$TMP/package-$PRGNAM
-OUTPUT=${OUTPUT:-/tmp}
-
-if [ "$ARCH" = "i586" ]; then
- SLKCFLAGS="-O2 -march=i586 -mtune=i686"
- LIBDIRSUFFIX=""
-elif [ "$ARCH" = "i686" ]; then
- SLKCFLAGS="-O2 -march=i686 -mtune=i686"
- LIBDIRSUFFIX=""
-elif [ "$ARCH" = "x86_64" ]; then
- SLKCFLAGS="-O2 -fPIC"
- LIBDIRSUFFIX="64"
-else
- SLKCFLAGS="-O2"
- LIBDIRSUFFIX=""
-fi
-
-set -e
-
-rm -rf $PKG
-mkdir -p $TMP $PKG $OUTPUT
-cd $TMP
-rm -rf $SRCNAM-$VERSION
-tar xvf $CWD/$SRCNAM-$VERSION.tar.bz2
-cd $SRCNAM-$VERSION
-chown -R root:root .
-find -L . \
- \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
- -o -perm 511 \) -exec chmod 755 {} \; -o \
- \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
- -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
-
-for patch in gnutls notestsapps fix_base64 ipv6 ice_config \
- multiple_listeners pj_ice_sess fix_turn_fallback \
- fix_ioqueue_ipv6_sendto add_dtls_transport; do
- patch -p1 -l <$CWD/patches/$patch.patch
-done
-
-PJFLAGS="-DPJ_ICE_MAX_CAND=256
- -DPJ_ICE_MAX_CHECKS=150
- -DPJ_ICE_COMP_BITS=2
- -DPJ_ICE_MAX_STUN=3
- -DPJSIP_MAX_PKT_LEN=8000
- -DPJ_ICE_ST_MAX_CAND=32"
-
-CFLAGS="$SLKCFLAGS -g $PJFLAGS" \
-CXXFLAGS="$SLKCFLAGS -g $PJFLAGS -std=gnu++11" \
-./aconfigure \
- --prefix=/usr \
- --libdir=/usr/lib${LIBDIRSUFFIX} \
- --disable-oss \
- --disable-sound \
- --disable-video \
- --enable-ext-sound \
- --disable-speex-aec \
- --disable-g711-codec \
- --disable-l16-codec \
- --disable-gsm-codec \
- --disable-g722-codec \
- --disable-g7221-codec \
- --disable-speex-codec \
- --disable-ilbc-codec \
- --disable-opencore-amr \
- --disable-silk \
- --disable-sdl \
- --disable-ffmpeg \
- --disable-v4l2 \
- --disable-openh264 \
- --disable-resample \
- --disable-libwebrtc \
- --enable-ssl=gnutls \
- --build=$ARCH-slackware-linux
-
-make
-make install DESTDIR=$PKG
-
-mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
-cp -a COPYING README-RTEMS README.txt $PKG/usr/doc/$PRGNAM-$VERSION
-cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
-
-mkdir -p $PKG/install
-cat $CWD/slack-desc > $PKG/install/slack-desc
-
-cd $PKG
-/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-tgz}
diff --git a/libraries/pjproject-ring/pjproject-ring.info b/libraries/pjproject-ring/pjproject-ring.info
deleted file mode 100644
index 6c60d0c8bb..0000000000
--- a/libraries/pjproject-ring/pjproject-ring.info
+++ /dev/null
@@ -1,10 +0,0 @@
-PRGNAM="pjproject-ring"
-VERSION="2.6"
-HOMEPAGE="https://www.pjsip.org/"
-DOWNLOAD="https://www.pjsip.org/release/2.6/pjproject-2.6.tar.bz2"
-MD5SUM="c347a672679e7875ce572e18517884b2"
-DOWNLOAD_x86_64=""
-MD5SUM_x86_64=""
-REQUIRES=""
-MAINTAINER="Mario Preksavec"
-EMAIL="mario at slackware dot hr"
diff --git a/libraries/pjproject-ring/slack-desc b/libraries/pjproject-ring/slack-desc
deleted file mode 100644
index b700136cf4..0000000000
--- a/libraries/pjproject-ring/slack-desc
+++ /dev/null
@@ -1,19 +0,0 @@
-# HOW TO EDIT THIS FILE:
-# The "handy ruler" below makes it easier to edit a package description.
-# Line up the first '|' above the ':' following the base package name, and
-# the '|' on the right side marks the last column you can put a character in.
-# You must make exactly 11 lines for the formatting to be correct. It's also
-# customary to leave one space after the ':' except on otherwise blank lines.
-
- |-----handy-ruler------------------------------------------------------|
-pjproject-ring: pjproject-ring (Multimedia Communication Library)
-pjproject-ring:
-pjproject-ring: PJSIP is a free and open source multimedia communication library
-pjproject-ring: written in C language implementing standard based protocols such as
-pjproject-ring: SIP, SDP, RTP, STUN, TURN, and ICE.
-pjproject-ring:
-pjproject-ring: This package includes patches from Ring project.
-pjproject-ring:
-pjproject-ring: Homepage: https://www.pjsip.org/
-pjproject-ring:
-pjproject-ring: